{"$defs":{"AppSpec":{"additionalProperties":false,"description":"The plugin's own app, opened inside Korsi's shell (decision 10).","properties":{"entry":{"default":"/","title":"Entry","type":"string"},"tabs":{"default":[],"items":{"$ref":"#/$defs/TabSpec"},"maxItems":8,"title":"Tabs","type":"array"}},"title":"AppSpec","type":"object"},"DataEgress":{"description":"Where the publisher says the organization's data goes. Declared, shown, and -- only for\n``instance`` placement -- enforced.","enum":["none","publisher","third_party"],"title":"DataEgress","type":"string"},"DataHandling":{"additionalProperties":false,"properties":{"egress":{"$ref":"#/$defs/DataEgress","default":"none"},"stores":{"default":[],"items":{"type":"string"},"maxItems":20,"title":"Stores","type":"array"},"retention_days":{"anyOf":[{"maximum":3650,"minimum":0,"type":"integer"},{"type":"null"}],"default":null,"title":"Retention Days"},"location":{"anyOf":[{"pattern":"^[A-Z]{2}$","type":"string"},{"type":"null"}],"default":null,"title":"Location"}},"title":"DataHandling","type":"object"},"ExtensionPoint":{"description":"Where in Korsi's own pages a plugin may show a panel (section 15).","enum":["record.panel","desk.widget"],"title":"ExtensionPoint","type":"string"},"LocalizedText":{"additionalProperties":false,"description":"A name or a sentence in the languages Korsi ships. At least one is required.\n\nPersian first, because it is the default language of the product; any one is accepted so a\npublisher writing in one language is not refused, and the store falls back through\n:meth:`pick`.","properties":{"fa":{"anyOf":[{"maxLength":500,"type":"string"},{"type":"null"}],"default":null,"title":"Fa"},"en":{"anyOf":[{"maxLength":500,"type":"string"},{"type":"null"}],"default":null,"title":"En"},"ar":{"anyOf":[{"maxLength":500,"type":"string"},{"type":"null"}],"default":null,"title":"Ar"}},"title":"LocalizedText","type":"object"},"PanelRecord":{"description":"Which record page a ``record.panel`` sits on.","enum":["case","meeting","document"],"title":"PanelRecord","type":"string"},"PanelSpec":{"additionalProperties":false,"description":"A panel in one of Korsi's pages, loaded only when a person opens it (decision 19).","properties":{"point":{"$ref":"#/$defs/ExtensionPoint"},"record":{"anyOf":[{"$ref":"#/$defs/PanelRecord"},{"type":"null"}],"default":null},"entry":{"title":"Entry","type":"string"},"names":{"anyOf":[{"$ref":"#/$defs/LocalizedText"},{"type":"null"}],"default":null}},"required":["point","entry"],"title":"PanelSpec","type":"object"},"Placement":{"description":"Where a plugin's code runs (section 17).","enum":["external","instance","none"],"title":"Placement","type":"string"},"PlanPeriod":{"enum":["monthly","yearly","once"],"title":"PlanPeriod","type":"string"},"PlanSpec":{"additionalProperties":false,"description":"A plan the plugin sells: an amount of MU and what each service costs from it.","properties":{"key":{"title":"Key","type":"string"},"names":{"$ref":"#/$defs/LocalizedText"},"period":{"$ref":"#/$defs/PlanPeriod"},"mu":{"anyOf":[{"exclusiveMinimum":0,"type":"number"},{"pattern":"^(?!^[-+.]*$)[+-]?0*(?:\\d{0,14}|(?=[\\d.]{1,19}0*$)\\d{0,14}\\.\\d{0,4}0*$)","type":"string"}],"title":"Mu"},"rates":{"additionalProperties":{"anyOf":[{"type":"number"},{"pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","type":"string"}]},"title":"Rates","type":"object"}},"required":["key","names","period","mu"],"title":"PlanSpec","type":"object"},"PluginScope":{"description":"Every scope a manifest may name. Renaming one is a breaking change to the plugin contract.","enum":["people.read","structure.read","cases.read","actions.read","decisions.read","meetings.read","meetings.transcript.read","documents.read","documents.text.read","calendar.read","memory.search","records.own","proposals.action","proposals.case","proposals.decision","proposals.calendar","sources.intake.message","sources.intake.document","wallet.consume","records.confidential"],"title":"PluginScope","type":"string"},"PluginType":{"description":"What a plugin mainly is. Its type decides how deep a review it gets, not what it may do.","enum":["intake_connector","insight_module","tool_module","app_module","knowledge_pack"],"title":"PluginType","type":"string"},"ProposalType":{"description":"What a plugin may propose into Korsi's own records (section 11).","enum":["action.create","case.change","decision.candidate","calendar.event.create"],"title":"ProposalType","type":"string"},"RecordTypeSpec":{"additionalProperties":false,"description":"A record type the plugin keeps in Korsi (section 10).","properties":{"key":{"title":"Key","type":"string"},"names":{"$ref":"#/$defs/LocalizedText"},"visibility":{"$ref":"#/$defs/RecordVisibility"},"title_field":{"default":"title","maxLength":64,"title":"Title Field","type":"string"},"schema":{"additionalProperties":true,"title":"Schema","type":"object"}},"required":["key","names","visibility","schema"],"title":"RecordTypeSpec","type":"object"},"RecordVisibility":{"description":"Who sees a plugin's record of a given type (decision 17).","enum":["organization","case","personal"],"title":"RecordVisibility","type":"string"},"RuntimeSpec":{"additionalProperties":false,"description":"Where the plugin's code runs, and how Korsi reaches it (section 17).\n\n``external``: the publisher names ``base_url``, its own server, and review approves it.\n``instance``: the publisher names an image by digest and the port it listens on; Korsi runs it\nbeside the instance and gives each installation its own address, so the manifest has no\n``base_url`` -- the address is the installation's, not the plugin's.","properties":{"placement":{"$ref":"#/$defs/Placement"},"base_url":{"anyOf":[{"format":"uri","maxLength":2083,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Base Url"},"image":{"anyOf":[{"maxLength":500,"type":"string"},{"type":"null"}],"default":null,"title":"Image"},"port":{"anyOf":[{"maximum":65535,"minimum":1,"type":"integer"},{"type":"null"}],"default":null,"title":"Port"},"egress":{"default":[],"items":{"type":"string"},"maxItems":20,"title":"Egress","type":"array"}},"required":["placement"],"title":"RuntimeSpec","type":"object"},"ScopeRequest":{"additionalProperties":false,"properties":{"required":{"default":[],"items":{"$ref":"#/$defs/PluginScope"},"title":"Required","type":"array"},"optional":{"default":[],"items":{"$ref":"#/$defs/PluginScope"},"title":"Optional","type":"array"}},"title":"ScopeRequest","type":"object"},"ServiceSpec":{"additionalProperties":false,"description":"A unit the plugin charges for, such as \"one email read\".","properties":{"key":{"pattern":"^[a-z][a-z0-9_.]{0,63}$","title":"Key","type":"string"},"names":{"$ref":"#/$defs/LocalizedText"}},"required":["key","names"],"title":"ServiceSpec","type":"object"},"SlotSpec":{"additionalProperties":false,"properties":{"provides":{"default":[],"items":{"type":"string"},"maxItems":5,"title":"Provides","type":"array"}},"title":"SlotSpec","type":"object"},"SupportSpec":{"additionalProperties":false,"properties":{"contact":{"anyOf":[{"maxLength":200,"type":"string"},{"type":"null"}],"default":null,"title":"Contact"},"url":{"anyOf":[{"format":"uri","maxLength":2083,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Url"}},"title":"SupportSpec","type":"object"},"TabSpec":{"additionalProperties":false,"properties":{"key":{"title":"Key","type":"string"},"names":{"$ref":"#/$defs/LocalizedText"},"path":{"title":"Path","type":"string"}},"required":["key","names","path"],"title":"TabSpec","type":"object"},"ToolSpec":{"additionalProperties":false,"description":"A tool the plugin offers Korsyar, through Korsi (decision 14). Read-only by contract.","properties":{"name":{"title":"Name","type":"string"},"description":{"$ref":"#/$defs/LocalizedText"},"input_schema":{"additionalProperties":true,"title":"Input Schema","type":"object"}},"required":["name","description"],"title":"ToolSpec","type":"object"},"UiSpec":{"additionalProperties":false,"properties":{"app":{"anyOf":[{"$ref":"#/$defs/AppSpec"},{"type":"null"}],"default":null},"panels":{"default":[],"items":{"$ref":"#/$defs/PanelSpec"},"maxItems":10,"title":"Panels","type":"array"}},"title":"UiSpec","type":"object"}},"additionalProperties":false,"description":"``korsi-plugin.yaml``: everything a plugin is allowed to be.","properties":{"schema":{"default":"korsi.plugin/v1","title":"Schema","type":"string"},"id":{"maxLength":128,"title":"Id","type":"string"},"publisher":{"title":"Publisher","type":"string"},"version":{"title":"Version","type":"string"},"plugin_api":{"default":">=1.0,<2.0","maxLength":40,"title":"Plugin Api","type":"string"},"type":{"$ref":"#/$defs/PluginType"},"names":{"$ref":"#/$defs/LocalizedText"},"summary":{"anyOf":[{"$ref":"#/$defs/LocalizedText"},{"type":"null"}],"default":null},"icon":{"anyOf":[{"format":"uri","maxLength":2083,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Icon"},"hue":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Hue"},"runtime":{"$ref":"#/$defs/RuntimeSpec"},"data_handling":{"$ref":"#/$defs/DataHandling"},"scopes":{"$ref":"#/$defs/ScopeRequest"},"record_types":{"default":[],"items":{"$ref":"#/$defs/RecordTypeSpec"},"maxItems":20,"title":"Record Types","type":"array"},"proposals":{"default":[],"items":{"$ref":"#/$defs/ProposalType"},"title":"Proposals","type":"array"},"intake":{"default":[],"items":{"type":"string"},"maxItems":2,"title":"Intake","type":"array"},"events":{"default":[],"items":{"type":"string"},"maxItems":50,"title":"Events","type":"array"},"tools":{"default":[],"items":{"$ref":"#/$defs/ToolSpec"},"maxItems":30,"title":"Tools","type":"array"},"ui":{"$ref":"#/$defs/UiSpec"},"settings_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"default":null,"title":"Settings Schema"},"services":{"default":[],"items":{"$ref":"#/$defs/ServiceSpec"},"maxItems":30,"title":"Services","type":"array"},"plans":{"default":[],"items":{"$ref":"#/$defs/PlanSpec"},"maxItems":10,"title":"Plans","type":"array"},"slots":{"$ref":"#/$defs/SlotSpec"},"support":{"$ref":"#/$defs/SupportSpec"}},"required":["id","publisher","version","type","names","runtime"],"title":"PluginManifest","type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://korsi.ai/schemas/korsi.plugin/v1.json"}