{"manifest_version":"1.0","substrate":"SLOE OS","description":"Deterministic action layer. Agents call abilities; the substrate executes them with schema validation, tenant attribution, and audit logging.","execute":{"method":"POST","path":"/abilities/execute","content_type":"application/json","body":{"ability":"<ability id from `abilities[].id`>","input":"<object matching that ability's input_schema>","context":"<optional object; tenantId is overridden by auth when a Bearer key is present>"},"example":{"ability":"contact.create","input":{"email":"person@example.com","name":"Person"}}},"rest":{"method":"POST","path":"/v1/abilities/<ability id>","content_type":"application/json","body":{"input":"<object matching that ability's input_schema>","context":"<optional, as for execute>"},"unknown_ability":404,"openapi":"/openapi.json"},"mcp":{"method":"POST","path":"/mcp","transport":"streamable-http","protocol_version":"2025-06-18","supported_protocol_versions":["2025-06-18","2025-03-26","2025-11-25"],"auth":"Bearer, required. This transport has no legacy-open mode.","tool_naming":"substrate_<ability id with dots replaced by underscores>","scoping":"tools/list returns only the abilities the presenting key is scoped to. An out-of-scope tool is reported as unknown, so a key cannot enumerate beyond its scope.","tenancy":"Tenant identity is taken from the key. Arguments naming a tenant are ignored."},"auth":{"scheme":"Bearer","header":"Authorization","mode":"enforced","required_for_abilities":true,"scoping":"Per-key ability allow-list. A key's scope is `*` (all), an array of ability ids, or an empty array (none). Ignored entirely in legacy-open mode.","note":"All ability calls require a valid Bearer key.","keysDb":true,"legacy_key_hits":0,"lifecycle":["key.issue","key.list","key.rotate","key.revoke","key.inspect"]},"response_envelope":{"success":{"ok":true,"ability":"<ability id>","result":"<handler return value — shape varies per ability>","duration":"<ms, integer>"},"failure":{"ok":false,"error":"<human-readable message>","ability":"<ability id, when known>"}},"errors":[{"http":400,"error":"Missing ability or input","meaning":"Request body lacked `ability` or `input`.","retryable":false},{"http":400,"error":"Unknown ability: <id>","meaning":"No such ability. Re-read this manifest.","retryable":false},{"http":400,"error":"Invalid input","meaning":"Input failed JSON-Schema validation. `details[]` carries the Ajv errors — fix the input and retry.","retryable":true},{"http":403,"error":"ability not in token scope","meaning":"Authenticated, but this key's allow-list excludes the ability. Needs a broader key.","retryable":false},{"http":501,"error":"Ability <id> not yet implemented","meaning":"Declared in the registry but no handler is wired. See `implemented: false`.","retryable":false},{"http":500,"error":"<handler message>","meaning":"Handler threw. May be a transient upstream failure.","retryable":true}],"counts":{"declared":79,"implemented":79,"unimplemented":0},"unimplemented":[],"domains":{"contact":["contact.create","contact.list","contact.get","contact.update"],"lead":["lead.create","lead.update_status","lead.list","lead.get"],"message":["message.send","message.send_markdown"],"task":["task.create","task.list","task.get","task.update_status"],"document":["document.generate","document.summarize"],"payment":["payment.initiate","payment.status","payment.list"],"file":["file.store"],"workflow":["workflow.trigger"],"event":["event.emit"],"plan":["plan.create","plan.execute","plan.verify","plan.learn"],"qa":["qa.checklist.create","qa.browser_check"],"memory":["memory.search","memory.save","memory.recall","memory.forget"],"lesson":["lesson.record"],"skill":["skill.list","skill.load"],"connection":["connection.list","connection.get","connection.revoke","connection.authorize"],"payout":["payout.send","payout.batch","payout.status","payout.list","payout.verify_account","payout.balance"],"email":["email.render"],"guide":["guide.publish","guide.list"],"sim":["sim.generate","sim.list"],"decision":["decision.record","decision.list"],"key":["key.issue","key.list","key.rotate","key.revoke","key.inspect"],"vertical":["vertical.list","vertical.manifest_get"],"web":["web.research","web.browse"],"workspace":["workspace.doc.create","workspace.doc.read","workspace.doc.patch","workspace.doc.list","workspace.doc.comment","workspace.doc.close"],"capability":["capability.discover"],"research":["research.verify"],"trust":["trust.preflight","trust.status","trust.publish"],"integration":["integration.app.toolkits","integration.app.connections","integration.app.connect","integration.app.tools","integration.app.execute","integration.search","integration.execute"]},"abilities":[{"id":"contact.create","domain":"contact","description":"Create a new contact (person or company)","implemented":true,"input_schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"company":{"type":"string"},"metadata":{"type":"object"},"idempotencyKey":{"type":"string"}}},"required":["name"]},{"id":"contact.list","domain":"contact","description":"List contacts for the current tenant (tenant-scoped read-back)","implemented":true,"input_schema":{"type":"object","required":[],"properties":{"status":{"type":"string"},"limit":{"type":"number"}}},"required":[]},{"id":"contact.get","domain":"contact","description":"Get a single contact by id (tenant-scoped)","implemented":true,"input_schema":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"}}},"required":["contactId"]},{"id":"contact.update","domain":"contact","description":"Update an existing contact","implemented":true,"input_schema":{"type":"object","required":["contactId","fields"],"properties":{"contactId":{"type":"string"},"fields":{"type":"object"}}},"required":["contactId","fields"]},{"id":"lead.create","domain":"lead","description":"Create a new lead in the pipeline","implemented":true,"input_schema":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"source":{"type":"string"},"vertical":{"type":"string"},"notes":{"type":"string"},"idempotencyKey":{"type":"string","description":"optional key so retries do not create duplicates"}}},"required":["contactId"]},{"id":"lead.update_status","domain":"lead","description":"Update a lead status (new, qualified, won, lost)","implemented":true,"input_schema":{"type":"object","required":["leadId","status"],"properties":{"leadId":{"type":"string"},"status":{"type":"string","enum":["new","qualified","proposal","won","lost"]}}},"required":["leadId","status"]},{"id":"lead.list","domain":"lead","description":"List leads for your tenant, optionally filtered by status","implemented":true,"input_schema":{"type":"object","properties":{"status":{"type":"string"},"limit":{"type":"number"}}},"required":[]},{"id":"lead.get","domain":"lead","description":"Get one lead by id, scoped to your tenant","implemented":true,"input_schema":{"type":"object","required":["leadId"],"properties":{"leadId":{"type":"string"}}},"required":["leadId"]},{"id":"message.send","domain":"message","description":"Send a message through any channel","implemented":true,"input_schema":{"type":"object","required":["to","channel","message"],"properties":{"to":{"type":"string"},"channel":{"type":"string","enum":["whatsapp","telegram","sms","email"]},"message":{"type":"string"},"attachments":{"type":"array","items":{"type":"string"}}}},"required":["to","channel","message"]},{"id":"task.create","domain":"task","description":"Create a task for a human or agent","implemented":true,"input_schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"assignedTo":{"type":"string"},"dueInHours":{"type":"number"},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"vertical":{"type":"string"},"idempotencyKey":{"type":"string","description":"optional key so retries do not create duplicates"}}},"required":["title"]},{"id":"task.list","domain":"task","description":"List tasks for your tenant, optionally filtered by status","implemented":true,"input_schema":{"type":"object","properties":{"status":{"type":"string"},"limit":{"type":"number"}}},"required":[]},{"id":"task.get","domain":"task","description":"Get one task by id, scoped to your tenant","implemented":true,"input_schema":{"type":"object","required":["taskId"],"properties":{"taskId":{"type":"string"}}},"required":["taskId"]},{"id":"task.update_status","domain":"task","description":"Update a task status (pending, in_progress, done, cancelled)","implemented":true,"input_schema":{"type":"object","required":["taskId","status"],"properties":{"taskId":{"type":"string"},"status":{"type":"string","enum":["pending","in_progress","done","cancelled"]}}},"required":["taskId","status"]},{"id":"document.generate","domain":"document","description":"Generate a document from a template","implemented":true,"input_schema":{"type":"object","required":["template","data"],"properties":{"template":{"type":"string"},"data":{"type":"object"},"format":{"type":"string","enum":["pdf","docx","md"],"default":"pdf"}}},"required":["template","data"]},{"id":"document.summarize","domain":"document","description":"Summarize a document or text","implemented":true,"input_schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string"},"length":{"type":"string","enum":["short","medium","long"],"default":"medium"}}},"required":["text"]},{"id":"payment.initiate","domain":"payment","description":"Initiate a payment, invoice, or charge. provider 'stripe' (default) creates a Stripe Payment Link (Connect direct-charge + application_fee when the tenant is connected); provider 'paystack' creates a Paystack checkout SPLIT charge on SLOE's platform account routed to the tenant's collections subaccount (requires customerEmail).","implemented":true,"input_schema":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"number"},"currency":{"type":"string"},"provider":{"type":"string","enum":["stripe","paystack"]},"customerEmail":{"type":"string"},"callbackUrl":{"type":"string"},"recipientId":{"type":"string"},"description":{"type":"string"},"contactId":{"type":"string"},"leadId":{"type":"string"},"idempotencyKey":{"type":"string"}}},"required":["amount","currency"]},{"id":"payment.status","domain":"payment","description":"Get a payment's current status (tenant-scoped read-back)","implemented":true,"input_schema":{"type":"object","required":[],"properties":{"paymentId":{"type":"string"},"providerRef":{"type":"string"}}},"required":[]},{"id":"payment.list","domain":"payment","description":"List payments for the current tenant (tenant-scoped)","implemented":true,"input_schema":{"type":"object","required":[],"properties":{"status":{"type":"string"},"limit":{"type":"number"}}},"required":[]},{"id":"file.store","domain":"file","description":"Store a file in R2 storage","implemented":true,"input_schema":{"type":"object","required":["filename","content"],"properties":{"filename":{"type":"string"},"content":{"type":"string"},"contentType":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"required":["filename","content"]},{"id":"workflow.trigger","domain":"workflow","description":"Trigger an n8n workflow or multi-step process","implemented":true,"input_schema":{"type":"object","required":["workflow"],"properties":{"workflow":{"type":"string"},"input":{"type":"object"}}},"required":["workflow"]},{"id":"event.emit","domain":"event","description":"Emit a substrate event for other systems to react to","implemented":true,"input_schema":{"type":"object","required":["event"],"properties":{"event":{"type":"string"},"payload":{"type":"object"}}},"required":["event"]},{"id":"plan.create","domain":"plan","description":"Create an execution plan from a goal — breaks into phases with dependencies, checks templates and lessons","implemented":true,"input_schema":{"type":"object","required":["goal"],"properties":{"goal":{"type":"string"},"constraints":{"type":"array","items":{"type":"string"}},"vertical":{"type":"string"},"type":{"type":"string"}}},"required":["goal"]},{"id":"plan.execute","domain":"plan","description":"Execute a specific phase of a plan — runs the ability chain for that phase","implemented":true,"input_schema":{"type":"object","required":["planId"],"properties":{"planId":{"type":"string"},"phase":{"type":"number"}}},"required":["planId"]},{"id":"plan.verify","domain":"plan","description":"Verify a phase completed successfully — checks all ability results","implemented":true,"input_schema":{"type":"object","required":["planId"],"properties":{"planId":{"type":"string"},"phase":{"type":"number"}}},"required":["planId"]},{"id":"plan.learn","domain":"plan","description":"Extract lessons from a completed plan — saves template for reuse, feeds learning engine","implemented":true,"input_schema":{"type":"object","required":["planId"],"properties":{"planId":{"type":"string"}}},"required":["planId"]},{"id":"message.send_markdown","domain":"message","description":"Send an email rendered from markdown to styled HTML. Use for runbooks, handoffs, incident reports, ops emails — anywhere markdown is the natural source-of-truth.","implemented":true,"input_schema":{"type":"object","required":["to","subject","markdown"],"properties":{"to":{"oneOf":[{"type":"string","description":"Single recipient email"},{"type":"array","items":{"type":"string"},"description":"Multiple recipients"}]},"subject":{"type":"string"},"markdown":{"type":"string","description":"Markdown source — headings, lists, tables, code blocks, links all render with styled HTML"},"from":{"type":"string","description":"Sender (default: \"Sebenza Ops <noreply@sebenzas.com>\")"},"replyTo":{"type":"string"},"brand":{"type":"string","description":"Brand color hex (default #1e3a5f Sebenza navy)"}}},"required":["to","subject","markdown"]},{"id":"qa.checklist.create","domain":"qa","description":"Generate a branded, hosted QA checklist for any Sloe Labs product. Substrate hosts it at /qa/<id>; non-technical testers run plain-language checks, submit in-page, and the substrate stores results + emits a substrate event (default qa.results.received) so UAT pipelines pick them up automatically.","implemented":true,"input_schema":{"type":"object","required":["product","tests"],"properties":{"product":{"type":"string","description":"Product name shown in the header (e.g. \"Sebenza\")"},"phase":{"type":"string","description":"Optional phase / release label (e.g. \"Phase 08 — Sales & Billing\")"},"context":{"type":"string","description":"Optional one-paragraph context shown above the checks"},"prepared_by":{"type":"string","description":"Who prepared the checklist (default: authed tenant or \"Sloe Labs\")"},"result_event":{"type":"string","description":"Substrate event name emitted on each submission (default \"qa.results.received\")"},"tests":{"type":"array","minItems":1,"description":"The checks a tester runs, in order","items":{"type":"object","required":["title","expected_good"],"properties":{"title":{"type":"string","description":"Short check name"},"steps":{"type":"array","items":{"type":"string"},"description":"Plain-language steps the tester performs"},"expected_good":{"type":"string","description":"What a passing result looks like"},"expected_bad":{"type":"string","description":"What a failing result looks like"},"where":{"type":"string","description":"Where in the product to run this check"}}}}}},"required":["product","tests"]},{"id":"memory.search","domain":"memory","description":"Semantic search over a scoped memory collection. Sends TEXT; the substrate embeds server-side (gemini-embedding-001@768), cosine-ranks, applies recency decay, returns top matches. Auth-required; the collection must be in the caller key's scope.","implemented":true,"input_schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","description":"Natural-language query"},"collection":{"type":"string","description":"Qdrant collection (must be in the key's scope; defaults to the key's first scoped collection)"},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max hits (default 5)"},"filter":{"type":"object","description":"Optional Qdrant payload filter"}}},"required":["query"]},{"id":"memory.save","domain":"memory","description":"Embed and store a text memory into a scoped collection (gemini-embedding-001@768, stamped with embedder id + timestamp; collection auto-created). Auth-required; collection must be in the caller key's scope.","implemented":true,"input_schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","description":"The memory text (<= 8000 chars)"},"collection":{"type":"string","description":"Target collection (must be in the key's scope; defaults to the key's first)"},"category":{"type":"string","description":"e.g. semantic | episodic | procedural"},"metadata":{"type":"object","description":"Extra payload fields stored alongside the memory"}}},"required":["content"]},{"id":"memory.recall","domain":"memory","description":"Search a scoped collection and return the top matches formatted as a ready-to-inject context block. Auth-required.","implemented":true,"input_schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"collection":{"type":"string"},"k":{"type":"integer","minimum":1,"maximum":20,"description":"How many memories to include (default 5)"}}},"required":["query"]},{"id":"memory.forget","domain":"memory","description":"Delete points from a scoped collection by id list or payload filter. Auth-required.","implemented":true,"input_schema":{"type":"object","properties":{"collection":{"type":"string"},"ids":{"type":"array","items":{},"description":"Point ids to delete"},"filter":{"type":"object","description":"Qdrant payload filter (alternative to ids)"}}},"required":[]},{"id":"lesson.record","domain":"lesson","description":"Append a lesson to the SLOE OS lessons inbox for the consolidator pipeline (dedupe -> skills regen -> guardrail promotion). Append-only; does NOT write lessons.json/skills/guardrails directly. Auth-required.","implemented":true,"input_schema":{"type":"object","required":["title","category","lesson"],"properties":{"title":{"type":"string"},"category":{"type":"string","enum":["engineering","ops","business","architecture","security"]},"triggers":{"type":"array","items":{"type":"string"},"description":"Keywords that should surface this lesson later"},"severity":{"type":"string","enum":["critical","high","medium","low"]},"context":{"type":"string","description":"What you were doing when this happened"},"lesson":{"type":"string","description":"The non-obvious insight"},"fix":{"type":"string","description":"The specific fix or action to take"},"tags":{"type":"array","items":{"type":"string"}},"reusable":{"type":"boolean"}}},"required":["title","category","lesson"]},{"id":"skill.list","domain":"skill","description":"List the available skill/knowledge packs (auto-generated from lessons) with one-line descriptions. Auth-required.","implemented":true,"input_schema":{"type":"object","properties":{"domain":{"type":"string","description":"Optional filter by domain-name substring"}}},"required":[]},{"id":"skill.load","domain":"skill","description":"Load a skill/knowledge pack by name (e.g. engineering, ops, security, architecture-gaps, tools) and return its content for injection. Pass name 'guardrails' for the hard behavioural rules. Auth-required.","implemented":true,"input_schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Skill domain name (stem of memory/skills/<name>.md) or 'guardrails'"}}},"required":["name"]},{"id":"connection.list","domain":"connection","description":"List the external-account connections wired for your tenant (Phase D). Each row shows a service (stripe|email|whatsapp…), its status (pending|connected|revoked), and the external ref (e.g. a Stripe acct_…). No connection for a service means abilities fall back to the SLOE platform account. Auth-required; tenant-scoped.","implemented":true,"input_schema":{"type":"object","properties":{}},"required":[]},{"id":"connection.get","domain":"connection","description":"Get one connection for your tenant by service (tenant-scoped read-back). Auth-required.","implemented":true,"input_schema":{"type":"object","required":["service"],"properties":{"service":{"type":"string","description":"Service key, e.g. stripe | email | whatsapp"}}},"required":["service"]},{"id":"connection.revoke","domain":"connection","description":"Revoke your tenant's connection for a service. After revoke, the affected abilities (payment.*/message.send) fall back to the SLOE platform account. Auth-required; tenant-scoped.","implemented":true,"input_schema":{"type":"object","required":["service"],"properties":{"service":{"type":"string","description":"Service key to revoke, e.g. stripe"}}},"required":["service"]},{"id":"payout.send","domain":"payout","description":"Disburse a single payment (e.g. an employee salary) to a bank account, on the tenant's OWN connected payout provider (paystack | stripe). amount is INTEGER MINOR UNITS (cents). Refuses if the tenant has no payout connection. Auth-required; tenant-scoped.","implemented":true,"input_schema":{"type":"object","required":["amount","beneficiary"],"properties":{"amount":{"type":"integer","minimum":1,"description":"Amount in minor units (cents)"},"currency":{"type":"string","description":"ISO currency (default ZAR)"},"beneficiary":{"type":"object","required":["name","accountNumber"],"properties":{"name":{"type":"string"},"accountNumber":{"type":"string"},"bankCode":{"type":"string","description":"Provider bank code (Paystack)"},"email":{"type":"string"},"country":{"type":"string"},"businessType":{"type":"string"},"payoutMethod":{"type":"string"}}},"reason":{"type":"string"},"idempotencyKey":{"type":"string","description":"Retry-safe key; also the payout id"},"employeeRef":{"type":"string"}}},"required":["amount","beneficiary"]},{"id":"payout.batch","domain":"payout","description":"Disburse many payments in one run (e.g. a full payroll). Paystack uses a native bulk transfer (requires OTP disabled on the tenant's account); Stripe loops. amounts are minor units. Auth-required; tenant-scoped.","implemented":true,"input_schema":{"type":"object","required":["transfers"],"properties":{"currency":{"type":"string"},"transfers":{"type":"array","minItems":1,"items":{"type":"object","required":["amount","beneficiary"],"properties":{"amount":{"type":"integer","minimum":1},"beneficiary":{"type":"object"},"reason":{"type":"string"},"idempotencyKey":{"type":"string"},"employeeRef":{"type":"string"}}}}}},"required":["transfers"]},{"id":"payout.status","domain":"payout","description":"Get a payout's current status (tenant-scoped read-back).","implemented":true,"input_schema":{"type":"object","properties":{"payoutId":{"type":"string"},"providerRef":{"type":"string"}}},"required":[]},{"id":"payout.list","domain":"payout","description":"List payouts for the current tenant (tenant-scoped).","implemented":true,"input_schema":{"type":"object","properties":{"status":{"type":"string"},"limit":{"type":"number"}}},"required":[]},{"id":"payout.verify_account","domain":"payout","description":"Validate a beneficiary bank account (AVS) on the tenant's payout provider before paying. Paystack /bank/validate (costs the tenant a small fee per check). Auth-required; tenant-scoped.","implemented":true,"input_schema":{"type":"object","properties":{"accountName":{"type":"string"},"accountNumber":{"type":"string"},"accountType":{"type":"string"},"bankCode":{"type":"string"},"countryCode":{"type":"string"},"documentType":{"type":"string"},"documentNumber":{"type":"string"},"recipient":{"type":"string"}}},"required":[]},{"id":"payout.balance","domain":"payout","description":"Get the tenant's payout provider balance / financial-account balance (feeds a float widget). Auth-required; tenant-scoped.","implemented":true,"input_schema":{"type":"object","properties":{}},"required":[]},{"id":"email.render","domain":"email","description":"Render a polished, on-brand HTML + plain-text email from a spec against the shared email vocabulary (templates: notice, invoice, receipt). Deterministic — no LLM, no send. Pass a per-tenant theme (brand colours, logo URL, firmName, tagline, siteUrl) so output is on-brand for any vertical. An agent composes the spec; compose with message.send to deliver.","implemented":true,"input_schema":{"type":"object","required":["spec"],"properties":{"spec":{"type":"object","required":["template","subject","props"],"properties":{"template":{"type":"string","enum":["notice","invoice","receipt"]},"subject":{"type":"string"},"props":{"type":"object"}}},"theme":{"type":"object"}}},"required":["spec"]},{"id":"guide.publish","domain":"guide","description":"Publish a user guide to a product's help centre (Cloudflare Pages) and return its public URL. Writes markdown into the product's tenant guides dir and runs the Guide Center build and deploy. The key's guideProducts allow-list decides which products it may publish to (fail-closed). Guide syntax: the Guide Center Markdown format.","implemented":true,"input_schema":{"type":"object","required":["product","slug","title","area","markdown"],"properties":{"product":{"type":"string","description":"recipe name, e.g. sebenza"},"slug":{"type":"string","description":"kebab-case; becomes the URL path"},"locale":{"type":"string","default":"en"},"title":{"type":"string"},"area":{"type":"string","description":"index section, e.g. Get paid / People / Start"},"summary":{"type":"string"},"time":{"type":"string","description":"e.g. 5 min"},"cost":{"type":"string","description":"e.g. R10"},"route":{"type":"string","description":"in-app route the guide explains"},"order":{"type":"number"},"markdown":{"type":"string","description":"guide body in the guide syntax (steps, `labels`, > ! callouts, slip blocks)"},"deploy":{"type":"boolean","default":true,"description":"false = write only, no build/deploy"}}},"required":["product","slug","title","area","markdown"]},{"id":"guide.list","domain":"guide","description":"List the guides currently live on a product's help centre (reads its guides.json manifest) — the corpus the in-app Help page and AI support assistant use.","implemented":true,"input_schema":{"type":"object","required":["product"],"properties":{"product":{"type":"string"},"locale":{"type":"string"},"publicUrl":{"type":"string","description":"override the help-centre base URL"}}},"required":["product"]},{"id":"sim.generate","domain":"sim","description":"Generate a playable case study from a GitHub PR and publish it to sims.sloelabs.com. Fetches the PR description + diff, has Claude write an interactive sim against the sim-kit contract, syntax-checks it, then builds + deploys the sims site and returns the public URL. Fail-closed: the key must carry simGenerate:true. Spends real model tokens; hand-crafted repo sims always win over generated ones on slug clash.","implemented":true,"input_schema":{"type":"object","required":["prUrl"],"properties":{"prUrl":{"type":"string","description":"https://github.com/owner/repo/pull/N"},"slug":{"type":"string","description":"kebab-case URL path; derived from the PR title if omitted"},"notes":{"type":"string","description":"operator guidance for the sim author (what to emphasise)"},"overwrite":{"type":"boolean","description":"replace an existing GENERATED sim with the same slug"}}},"required":["prUrl"]},{"id":"sim.list","domain":"sim","description":"List the playable case studies live on sims.sloelabs.com (reads the site's sims.json manifest).","implemented":true,"input_schema":{"type":"object","properties":{}},"required":[]},{"id":"qa.browser_check","domain":"qa","description":"Headless real-browser QA pass against a public URL: loads it in Chromium, returns HTTP status, title, console errors, failed requests (>=400), a pass boolean, and a stored R2 screenshot. Use after deploys and for client-site smoke checks. Internal/private hosts refused.","implemented":true,"input_schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"public http(s) URL to check"},"viewportWidth":{"type":"number","description":"default 1280"},"viewportHeight":{"type":"number","description":"default 800"},"waitMs":{"type":"number","description":"settle time after load; default 2500, max 10000"},"fullPage":{"type":"boolean","description":"full-page screenshot; default false"},"screenshot":{"type":"boolean","description":"capture + store screenshot; default true"}}},"required":["url"]},{"id":"decision.record","domain":"decision","description":"Record a settled decision with its WHY (and optional supersedes: D-NNN). Returns a citable per-tenant id (D-001…). Agents should record decisions the OPERATOR has settled — never their own preferences — and cite ids instead of re-litigating.","implemented":true,"input_schema":{"type":"object","required":["title","why"],"properties":{"title":{"type":"string","description":"The decision, one line"},"why":{"type":"string","description":"The reasoning — a decision without its why is unmaintainable"},"supersedes":{"type":"string","description":"Optional D-NNN this replaces"}}},"required":["title","why"]},{"id":"decision.list","domain":"decision","description":"List/search the tenant decision log (semantic). A settled decision outranks any agent recommendation — consult before proposing changes to established behavior.","implemented":true,"input_schema":{"type":"object","properties":{"query":{"type":"string","description":"What are you about to re-litigate?"},"limit":{"type":"integer","description":"max rows (default 10, cap 50)"}}},"required":[]},{"id":"key.issue","domain":"key","description":"Mint a new API key for a tenant. Returns the raw key ONCE (only a sha256 is stored). Admin keys may issue for any tenant; a tenant key may issue only for its own tenant and never wider than itself (abilities/collections must be a subset). Auth-required.","implemented":true,"input_schema":{"type":"object","required":["abilities"],"properties":{"tenant":{"type":"string","description":"Tenant id the key belongs to (^[a-z0-9][a-z0-9_-]{1,63}$). Default: the caller's tenant."},"name":{"type":"string","description":"Human label, e.g. \"console\", \"sebenza prod\". Default: the tenant."},"abilities":{"description":"\"*\" or an explicit list of ability ids. REQUIRED — a key with no stated scope is refused.","anyOf":[{"type":"string","enum":["*"]},{"type":"array","items":{"type":"string"}}]},"collections":{"type":"array","items":{"type":"string"},"description":"Memory collections this key may read/write (Qdrant). Default none."},"allowSubTenant":{"type":"boolean","description":"May scope calls to <tenant>__<sub> (one key, many orgs). Default false."},"persona":{"type":"string","description":"Optional per-key voice for /agent (max 4000 chars)."},"components":{"description":"gen-UI component scope: \"*\", a tier (basic|pro|enterprise) or an explicit list.","anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"guideProducts":{"type":"array","items":{"type":"string"},"description":"Help-centre products this key may publish to."},"simGenerate":{"type":"boolean","description":"May generate playable case studies."},"admin":{"type":"boolean","description":"Mint an ADMIN key (manage keys for any tenant). Admin callers only."},"expiresInDays":{"type":"number","description":"Optional expiry, 1..3650 days."}}},"required":["abilities"]},{"id":"key.list","domain":"key","description":"List API keys — never the secrets. Tenant · name · prefix · status · scopes · created · last used · expires. Admin keys see every tenant (optionally filtered) plus how many requests still authenticate through the legacy env blob; a tenant key sees only its own. Auth-required.","implemented":true,"input_schema":{"type":"object","properties":{"tenant":{"type":"string","description":"Filter to one tenant (admin only; ignored for tenant keys)."},"includeRevoked":{"type":"boolean","description":"Include revoked keys. Default false."}}},"required":[]},{"id":"key.rotate","domain":"key","description":"Rotate a key: mints a successor with the same tenant/name/scopes (raw key returned ONCE) and gives the old key an expiry — default 24h overlap — so consumers can be moved without an outage. Admin, or the key's own tenant. Auth-required.","implemented":true,"input_schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Key id (key_…) from key.list."},"overlapHours":{"type":"number","description":"How long the OLD key keeps working. 0..336, default 24."}}},"required":["id"]},{"id":"key.revoke","domain":"key","description":"Revoke a key immediately (takes effect within the 30s auth cache). Admin, or the key's own tenant. Revoking the key you are calling with needs confirmSelf:true. Auth-required.","implemented":true,"input_schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Key id (key_…) from key.list."},"reason":{"type":"string","description":"Why (logged to the key's event trail)."},"confirmSelf":{"type":"boolean","description":"Required to revoke the calling key itself."}}},"required":["id"]},{"id":"key.inspect","domain":"key","description":"What can THIS key do — tenant, the abilities it may call (expanded), collections, sub-tenant flag, admin, and — once it resolves through the keys table — id/prefix/created/expires/last used. What an MCP host or a generated docs page renders from. Auth-required; no admin needed.","implemented":true,"input_schema":{"type":"object","properties":{}},"required":[]},{"id":"vertical.list","domain":"vertical","description":"List the verticals the substrate serves (from each vertical's manifest): id, name, version, whether a SURFACE manifest exists, its screen ids. A vertical is a manifest, not a fork.","implemented":true,"input_schema":{"type":"object","properties":{}},"required":[]},{"id":"vertical.manifest_get","domain":"vertical","description":"Get a vertical's SURFACE manifest — the runtime half: nouns, screens as gen-UI node types with bindings, capture types (Step 2), signals (Step 3), and actions that are a substrate ability or a guarded host endpoint, never SQL. Runs manifest-lint on every serve and REFUSES a surface that fails it (findings by path). section='all' returns the whole manifest (provisioning keys included). No tenant data, no secrets; any authenticated key may read.","implemented":true,"input_schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"vertical slug, e.g. 'sebenza'"},"section":{"type":"string","enum":["surface","all"],"description":"default 'surface'"}}},"required":["id"]},{"id":"web.research","domain":"web","description":"Answer a question from the open web: searches, reads the top pages, and writes an answer where every claim cites its source [n]. Returns the answer, the sources (url, title, whether read, whether cited) and a grounded flag. Read-only: it never clicks, types or submits. Private and SLOE-internal addresses are never read.","implemented":true,"input_schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","description":"what to find out (max 1000 chars)"},"maxSources":{"type":"integer","minimum":1,"maximum":8,"description":"pages to read; default 5"},"freshness":{"type":"string","enum":["pd","pw","pm","py"],"description":"only results from the past day/week/month/year"},"allowedHosts":{"type":"array","items":{"type":"string"},"description":"restrict sources to these hosts (exact or *.suffix)"}}},"required":["question"]},{"id":"web.browse","domain":"web","description":"Do a task on the web with a real browser (hosted, off SLOE's network): the agent looks at the page and clicks, types, scrolls and navigates until it can answer. Returns status done|held|stopped|error, the answer, every step taken, and a final screenshot. It never types passwords, card numbers or codes, and it stops with status 'held' before submitting any form that sends, buys, books or logs in, so a person can decide. Private and SLOE-internal addresses are never visited.","implemented":true,"input_schema":{"type":"object","required":["task"],"properties":{"task":{"type":"string","description":"what to do and what to report back (max 2000 chars)"},"startUrl":{"type":"string","description":"page to start on; default a search engine"},"allowedHosts":{"type":"array","items":{"type":"string"},"description":"only visit these hosts (exact or *.suffix)"},"maxSteps":{"type":"integer","minimum":1,"maximum":30,"description":"default 15"},"maxSeconds":{"type":"integer","minimum":20,"maximum":300,"description":"wall-clock budget; default 120"}}},"required":["task"]},{"id":"workspace.doc.create","domain":"workspace","description":"Create a hosted, block-addressed working document. Substrate serves it at /doc/<id> behind a signed expiring link; humans read and edit it in a browser (phone included) while agents patch it by block, and every change emits a substrate event so git-sync / Telegram / UAT pipelines pick it up. Create the SKELETON FIRST — title plus one `pending` block per section — then fill each with workspace.doc.patch, so the reader watches it fill and a second agent can claim a different section.","implemented":true,"input_schema":{"type":"object","required":["title","blocks"],"properties":{"title":{"type":"string","description":"document title, shown in the header"},"product":{"type":"string","description":"recipe name, e.g. sebenza — scopes listing"},"kind":{"type":"string","enum":["plan","handoff","research","report","brief","uat","note"],"default":"note"},"owner":{"type":"string","description":"who the document is FOR (the human), shown in the header"},"edit_event":{"type":"string","default":"workspace.doc.edited","description":"substrate event emitted on every change"},"blocks":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"object","required":["type"],"description":"One addressable section. `pending` = a placeholder with a written intent (create the skeleton FIRST, then fill each one — the human watches it fill and a second agent can claim a different section). `markdown` = prose. `ui` = a UIPrimitive from the ui__render vocabulary, validated against the same per-key component scope as a chat render. `decision` = a question with options a human taps. `checks` = QA-style checks a tester runs.","properties":{"type":{"type":"string","enum":["pending","markdown","ui","decision","checks"]},"id":{"type":"string","description":"stable address, e.g. \"goals\" — auto-assigned (b1, b2…) if omitted. Patches target this."},"intent":{"type":"string","description":"pending: what this section will contain. A contract the filling agent is held to."},"content":{"type":"string","description":"markdown: the body"},"node":{"type":"object","description":"ui: a UIPrimitive (chart / datagrid / stat / table / grid / card / list / text)"},"question":{"type":"string","description":"decision: what is being decided"},"options":{"type":"array","description":"decision: 2-8 options, string or {label,value,description}"},"chosen":{"type":["string","null"],"description":"decision: the selected value"},"tests":{"type":"array","description":"checks: [{title, steps[], expected_good, expected_bad, where}]"}}}}}},"required":["title","blocks"]},{"id":"workspace.doc.read","domain":"workspace","description":"Read a hosted document: every block with its id and rev, plus its share links. Read before patching — the revs you get back are what if_block_rev guards against.","implemented":true,"input_schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"include_comments":{"type":"boolean","default":false},"include_history":{"type":"boolean","default":false}}},"required":["id"]},{"id":"workspace.doc.patch","domain":"workspace","description":"Change a hosted document by block. ALL-OR-NOTHING: if any op fails nothing is written. Two optional concurrency guards — `if_revision` (whole doc) and per-op `if_block_rev` (one block); a mismatch returns conflict:true and changes nothing, so re-read and retry. `claim` marks a block as yours for 15 minutes and blocks other actors' writes to it — this is how two agents work one document at once without a merge.","implemented":true,"input_schema":{"type":"object","required":["id","ops"],"properties":{"id":{"type":"string"},"if_revision":{"type":"number","description":"doc-level optimistic guard; 409 on mismatch"},"actor":{"type":"string","description":"who is writing (defaults to the key's tenant). Claims are per-actor."},"force":{"type":"boolean","description":"amend a closed document"},"ops":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["replace","insert_after","insert_before","delete","claim","release"]},"block_id":{"type":"string","description":"target (or anchor, for inserts)"},"block":{"type":"object","description":"the new block, for replace / insert_*"},"if_block_rev":{"type":"number","description":"block-level optimistic guard; 409 on mismatch"},"force":{"type":"boolean","description":"override another actor's live claim"}}}}}},"required":["id","ops"]},{"id":"workspace.doc.list","domain":"workspace","description":"List this tenant's hosted documents, newest first, with how many sections are still pending.","implemented":true,"input_schema":{"type":"object","properties":{"product":{"type":"string"},"kind":{"type":"string"},"owner":{"type":"string"},"status":{"type":"string","enum":["open","closed"]},"limit":{"type":"number","default":50,"maximum":200}}},"required":[]},{"id":"workspace.doc.comment","domain":"workspace","description":"Comment on a hosted document, optionally anchored to one block and threaded under a parent comment. Emits workspace.doc.commented.","implemented":true,"input_schema":{"type":"object","required":["id","body"],"properties":{"id":{"type":"string"},"block_id":{"type":"string","description":"anchor the comment to one section"},"parent":{"type":"string","description":"comment_id this replies to"},"author":{"type":"string"},"body":{"type":"string"}}},"required":["id","body"]},{"id":"workspace.doc.close","domain":"workspace","description":"Freeze a hosted document as a record. Further patches need force:true. Emits workspace.doc.closed carrying the final markdown, which is what a git-sync subscriber commits.","implemented":true,"input_schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"disposition":{"type":"string","description":"how it ended, e.g. \"shipped as Phase 21\""}}},"required":["id"]},{"id":"capability.discover","domain":"capability","description":"Search the live scoped capability registry before claiming a capability is absent.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"query":{"type":"string","minLength":1,"maxLength":200}},"required":[]},"required":[]},{"id":"research.verify","domain":"research","description":"Search current web sources and capture registered official pages. Returns observations, not automatic truth.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"query":{"type":"string","minLength":1,"maxLength":500},"claim":{"type":"string","minLength":1,"maxLength":2000},"urls":{"type":"array","items":{"type":"string","minLength":1,"maxLength":2000},"maxItems":3}},"required":[],"anyOf":[{"required":["query"]},{"required":["urls"]}]},"required":[]},{"id":"trust.preflight","domain":"trust","description":"Create a time-bounded run and single-use permits for exact actions. Attach fresh server receipts for consequential claims.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"task":{"type":"string","minLength":1,"maxLength":4000},"actions":{"type":"array","maxItems":20,"items":{"type":"object","additionalProperties":false,"properties":{"ability":{"type":"string","minLength":1,"maxLength":100},"input":{"type":"object"}},"required":["ability","input"]}},"claims":{"type":"array","maxItems":20,"items":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string","minLength":1,"maxLength":2000},"receiptIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20,"uniqueItems":true}},"required":["text","receiptIds"]}}},"required":["task"]},"required":["task"]},{"id":"trust.status","domain":"trust","description":"Read a run, its block reasons, deadline and action outcomes.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"runId":{"type":"string","minLength":1,"maxLength":80}},"required":["runId"]},"required":["runId"]},{"id":"trust.publish","domain":"trust","description":"Publish a structured answer with observed, inference, or unverified labels. Outcome verification is not inferred from retrieval.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"claims":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string","minLength":1,"maxLength":2000},"status":{"type":"string","enum":["observed","inference","unverified"]},"receiptIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20,"uniqueItems":true}},"required":["text","status"]}}},"required":["claims"]},"required":["claims"]},{"id":"integration.app.toolkits","domain":"integration","description":"SloeIntegrations: search the apps a firm can connect, and how each signs in (signIn.oauth / signIn.key); with {toolkit}, the fields its key sign-in asks for.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"query":{"type":"string","maxLength":200},"limit":{"type":"integer","minimum":1,"maximum":50},"toolkit":{"type":"string","pattern":"^[a-z0-9][a-z0-9_]{0,63}$"}},"required":[]},"required":[]},{"id":"integration.app.connections","domain":"integration","description":"SloeIntegrations: list the firm's connected accounts, and which apps' Connect will succeed (null = see toolkits).","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{},"required":[]},"required":[]},{"id":"integration.app.connect","domain":"integration","description":"SloeIntegrations: start a sign-in (returns the consent URL), finish it after consent, connect with the firm's own key, or revoke a connection.","implemented":true,"input_schema":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"action":{"const":"start"},"toolkit":{"type":"string","pattern":"^[a-z0-9][a-z0-9_]{0,63}$"},"callbackUrl":{"type":"string","maxLength":2048}},"required":["action","toolkit","callbackUrl"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"key"},"toolkit":{"type":"string","pattern":"^[a-z0-9][a-z0-9_]{0,63}$"},"fields":{"type":"object","description":"Field name → value, as listed by integration.app.toolkits {toolkit}."}},"required":["action","toolkit","fields"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"finish"},"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"state":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"},"connectedAccountId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,200}$"},"sessionUri":{"type":"string","minLength":1,"maxLength":4096}},"required":["action","connectionId","state"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"revoke"},"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"}},"required":["action","connectionId"]}]},"required":[]},{"id":"integration.app.tools","domain":"integration","description":"SloeIntegrations: list the tools of one of the firm's connections, classed read / write / destructive.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"query":{"type":"string","maxLength":200}},"required":["connectionId"]},"required":["connectionId"]},{"id":"integration.app.execute","domain":"integration","description":"SloeIntegrations: run a tool on one of the firm's connections for the named signed-in user. Writes need an idempotency key; destructive tools need confirmed: true.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"tool":{"type":"string","pattern":"^[A-Z][A-Z0-9_]{1,159}$"},"arguments":{"type":"object","maxProperties":100},"actor":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"idempotencyKey":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"confirmed":{"type":"boolean"}},"required":["connectionId","tool","arguments","actor"]},"required":["connectionId","tool","arguments","actor"]},{"id":"integration.search","domain":"integration","description":"Discover approved tools or list the authenticated principal connections.","implemented":true,"input_schema":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"action":{"const":"connections"}},"required":["action"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"tools"},"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"query":{"type":"string","maxLength":1000}},"required":["connectionId"]}]},"required":[]},{"id":"integration.execute","domain":"integration","description":"Execute one version-pinned tool using an explicit owned or shared connection and server policy.","implemented":true,"input_schema":{"type":"object","additionalProperties":false,"properties":{"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"toolId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"arguments":{"type":"object","maxProperties":100},"idempotencyKey":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"}},"required":["connectionId","toolId","arguments"]},"required":["connectionId","toolId","arguments"]},{"id":"connection.authorize","domain":"connection","description":"Start or complete actor-bound consent, revoke an account, or manage an explicit expiring share.","implemented":true,"input_schema":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"action":{"const":"authorize"},"service":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"returnUrl":{"type":"string","maxLength":2048}},"required":["service"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"callback"},"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"state":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"},"sessionUri":{"type":"string","minLength":1,"maxLength":4096}},"required":["action","connectionId","state","sessionUri"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"revoke"},"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"}},"required":["action","connectionId"]},{"type":"object","additionalProperties":false,"properties":{"action":{"const":"share"},"connectionId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"principalId":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"},"toolIds":{"type":"array","uniqueItems":true,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":160,"pattern":"^[A-Za-z0-9][A-Za-z0-9_.:-]*$"}},"expiresAt":{"type":"string","maxLength":40}},"required":["action","connectionId","principalId","toolIds"]}]},"required":[]}]}