Start here - how to use this shipWhat this manual is, who it is for, and the chapter map.
This is the Ship's Manual: the curated "how do I use SPICE" guide. It serves three audiences from ONE source - the human operator (read this page at /board/manual), the in-app agents (query these same chapters with Tool.XQuery KnowledgeByTag('manual') or Tool.Search), and coding agents working on the repo (start at the root CLAUDE.md, which points to plans/AgentCollaboration.md).
Chapters, in reading order:
- 01 Operator daily loop - the captain's morning routine: which surfaces to check, in what order.
- 02 Platform concepts - what a part, board, agency, site and list ARE, with pointers to the deeper primers.
- 03 Agent operating manual - how an agent works inside the city: the tool surface, deltas, and the rules.
- 04 Dev and coding-agent setup - boot commands, ports, tooling, and the known traps.
- 05 Find your way - the bounded ladder an agent climbs to orient without loading the whole city.
- 06 Set up another radar or catalog - which SharePoint mechanism covers which case, in order.
- 07 Request a service - the service catalog and the intake procedure for a new request, research above all.
- 08 Enrol and run a worker - a seat on another machine: its composition, least privilege, the harness rules.
flowchart LR
subgraph MANUAL["The Ship's Manual - /board/manual"]
C0["00 Start here"] --> C1["01 Operator daily loop"]
C1 --> C2["02 Platform concepts"]
C2 --> C3["03 Agent operating manual"]
C3 --> C4["04 Dev setup"]
end
OP["Operator"] --> C0
AG["In-app agents - Tool.XQuery / Tool.Search"] --> C3
DEV["Coding agents - root CLAUDE.md"] --> C4
Beyond the manual: the full research library (every KnowledgeArticle, 60+) lives at /board/knowledge; the live self-description of the running platform is /about; every board is indexed at /board.
Operator daily loop - driving the shipThe captain's morning routine: the surfaces to check and act on, in order.
The daily loop, in order:
1. The bridge - /observatory?skin=bridge. The TODAY panel answers the morning questions at a glance: is the daily brief fresh, what fires next on the schedule, and the latest eval verdicts. The rest of the bridge shows the goal, instruments and milestone ladder.
2. The daily brief - /board/briefings. The Daily Intelligence brief lands each morning (06:35 UTC cadence, publish-gated by Eval.DailyBrief). One brief per day; if it is stale the TODAY panel says so.
3. Standing orders - /board/schedule. Every declared Schedule with its gate verdict, last-fired and next-fire time, and catch-up flags. This is where you see whether the cadence actually ran.
4. Quality - /board/evals. Declared-eval coverage plus recent verdict history. An honest Fail here is signal, not noise.
5. Health - /board/health. The honest per-agency grading of the living districts.
6. Decisions waiting on you - /approvals (quorum approvals) and the Hub inbox at /sites/Hub.
7. Money - /board/credits (the TEST/LIVE honesty badge) and /board/outcome (cost-per-outcome).
Everything else is indexed at /board - notably /board/gaps (what the city says is missing), /board/agencies (the roster), /board/registry (the yellow pages: every tool's mission, inputs and outputs), and /board/quests (suggested next actions).
Rule of thumb: the boards are projections of the same spine the agents read - if a board looks wrong, the data is wrong, not the paint.
Platform concepts - what things areThe five nouns that explain the whole platform, with pointers to the deeper primers.
Five nouns explain the platform:
- PART - the unit of everything. A declared XML element (Tool, Board, Agency, Schedule, Skill, Workflow, KnowledgeArticle, ...) in the merged spine (SPICE.Web/Config/Parts.xml plus each app's Parts.*.xml), validated against SAF-Parts.xsd at boot. Behavior is declared as data; C# is only the engine that executes parts.
- BOARD - a read-only projection of the spine or a live store, rendered through XSLT at /board/{key} with an XML twin at /board/{key}/data. Around 35 exist; /board indexes them.
- AGENCY (district) - a crew of agents with recurring, gated work (Wisdom, Research, Academy, Content, Genesis, Strategy, PartsFactory, ...). Declaring an Agency as data creates its district and eval node.
- SITE and LIST - the SharePoint-shaped content substrate. Sites hold lists; lists hold typed items; CAML-style queries read them. The Hub site (/sites/Hub) is the operator command center.
- EVAL - the anti-theatre instrument. Declared evals gate ships and publishes (for example the daily brief only publishes when Eval.DailyBrief passes); verdicts land on /board/evals.
Deeper primers - all on /board/knowledge, do not duplicate them, read them:
- KB.PlatformInOneSentence - the elevator version.
- KB.SystemState - the narrative state of the system with the honest ALIVE versus PARKED ledger.
- KB.SpicePrinciples - the layered-architecture rules every contributor must follow.
- KB.AntiPatterns - the numbered anti-pattern ledger; cite by number.
Agent operating manual - working inside the cityFor in-app agents: the tool surface, how to change the city, and the rules that keep it coherent.
How an agent operates inside SPICE:
READ before you act - the city is self-describing:
- Tool.XQuery - query the merged spine with XQuery 3.1: any part kind, the cycle ledger, or knowledge by tag (KnowledgeByTag('manual') returns this manual). The spine is the single source of truth.
- Tool.Search - lexical plus vector search over the KnowledgeArticle corpus when you do not know the exact id or tag.
- Tool.FetchKnowledge - resolve live data slots (for example ListView('Issues', limit=5)) declared as KnowledgeRef elements; this fetches CURRENT list rows, a different concern from the static KB articles.
- Tool.Advise - synthesized advice grounded in the city's filed wisdom.
CHANGE the city only through declared channels:
- Emit a ProvisioningDelta - schema-valid XML in the SAF namespace using the closed operation vocabulary. Never invent element names; follow the taught skeleton (see KB.ProvisioningDeltaPattern).
- Runtime list writes must prefix the item key with "item:" or the row is invisible to every list view.
- Structural change beyond a delta is not yours - raise it via the Hub inbox for the operator.
THE RULES (non-negotiable, from the platform DNA):
- Declare-first: prompts, templates, thresholds, cron, vocabularies are DATA (parts, settings, knowledge), never code literals.
- Reuse the existing part before proposing a new one.
- XML inside the platform; JSON only at external boundaries via an XSLT adaptor.
- Honest output: never return an empty final silently; an eval must separate infra-error from subject-error.
Protocol references on /board/knowledge: KB.AgenticToolUse (tool-use protocol), KB.ReActProtocol (the reason-act loop), KB.AgentProtocolChannels and KB.AgentSurfaceContract (how agents talk to the platform).
source: plans/AgentCollaboration.md
Dev setup - booting, tooling and the trapsFor developers and coding agents: boot commands, ports, offline tools, and the known footguns.
Read plans/AgentCollaboration.md FIRST - it is the canonical brief for any agent touching the repo. This chapter is the environment cheat-sheet.
BOOT (always Development, always the explicit port):
ASPNETCORE_ENVIRONMENT=Development dotnet run --project SPICE.Web --urls http://localhost:5198
A bare dotnet run boots :5000 with the Echo stub and the wrong environment. Development uses the free local LLM gateway; Production defaults to a PAID provider - keep daily work on Development.
OFFLINE TOOLS (query before you grep):
- tools/parts-xq.ps1 - XPath/XQuery over the merged part spine; one query beats a 14-file grep.
- tools/spice-validate - XSD plus well-formedness over the spine; run after ANY part-XML edit.
- tools/spice-edit.ps1 - EDIT the spine by part Id (set Attr=Value, text Child, insert after an Id, replace, remove) as a byte-exact patch of that part only, and diff the spine against git part by part (spice-edit diff). Use it instead of text replacement; SaxonCS-HE has no XQuery Update.
- tools/types-map - the C# structure map; also served at /agency/types.
- tools/obs-smoke.ps1 - served smoke against :5198.
THE TRAPS (each cost a real day; cite the anti-pattern ledger, KB.AntiPatterns, by number):
- Manifest boot-rewrite (#29): booting the app (Served tests boot too) rewrites SAF-Site-Manifest.xml. Stage your clean edit with git add BEFORE anything boots, then discard the working-tree churn. Never commit manifest churn.
- Shared dev DB: tests and the running app share the Development database. Test cleanup must be key-scoped, never wholesale, or it wipes the operator's data.
- Assert the served surface (#23/#25): unit tests bypass XSD and the reader path. A cycle is done only when the WRITE round-trips through the SERVED read (boot, hit the endpoint, see the data).
- Razor fallbacks: pages render as an XML model through XSLT; never add a Razor view or keep one as a fallback. A null model is a 404. The deleted list-form fallback read rows with no permission or approval check and showed Pending pages to readers (AGT.73).
VERIFY before calling anything done: full test suite green, spice-validate clean, smoke the touched endpoints on :5198, and the served round-trip proven.
source: plans/AgentCollaboration.md
Find your way - progressive disclosure for an agentThe bounded ladder an agent climbs to orient in this city without loading it: /about for the shape, one XQuery for the index of a kind, a filtered slice for the view, by-id for one part in full, then the served surface for the truth. Modelled on SharePoint Site Settings to list to View to item - four bounded levels, each earning the next.
SharePoint never hands you a site. It hands you Site Settings - one screen of CATEGORIES - then a list, then a VIEW of that list with chosen columns and a row limit, then one item's form. Four levels, each bounded, each earning the next. That is progressive disclosure, and it is what an agent arriving in this city needs too, because the spine holds roughly 90 knowledge articles, 66 skills and 51 tools and reading them all is not orientation, it is drowning. THE LADDER. Level 0, the shape: GET /about returns the part library as counts by kind. One page, no detail, and it tells you what KINDS of thing exist here before you ask about any one of them - the Site Settings level. Level 1, the index of a kind: Tool.XQuery with count(//Skill) or with a name-only projection such as for $s in //Skill return $s/@Id. Names, never bodies. This is the list level, and the discipline is to project only the attributes you need - the XQuery equivalent of ViewFields. Level 2, a bounded slice: add a predicate and a limit - //Skill[@Category='Review'] or subsequence(//KnowledgeArticle,1,10). This is the VIEW: a filtered, ordered, row-limited window, not the whole list. Tool.Search does the same job when you do not know the id or tag. Level 3, one thing in full: GET /agency/parts/by-id/{id} for a single part, or KnowledgeByTag('manual') for a tagged set. This is the Display form - full detail, one item, asked for deliberately. Level 4, the truth: hit the SERVED surface the change should expose and confirm the reader resolves what the writer produced. A part that validates is not a part that works. THE ANTI-PATTERN this exists to prevent: loading the corpus. Greping 14 part files, or reading every KnowledgeArticle, costs a large fraction of a context window and returns mostly what you did not need - and the thing you were looking for arrives buried rather than framed. One XPath at Level 1 beats a fan-out grep, every time, and it is faster than reading this sentence took. THE RULE: never descend a level you were not sent to by the level above. If Level 0 does not show a kind, you do not need its parts. If Level 1's names do not include your target, drill sideways with Tool.Search rather than downwards into bodies. Each level should answer whether the next one is worth opening.
source: plans/AgentCollaboration.md
Set up another radar or catalog - the procedureThe runbook for a second radar (or any spec-generated, catalog-shaped site): which SharePoint mechanism covers which case, the steps in order, and the traps already paid for. SharePoint's answer is the same: a site template for the site, a solution package for a new kind, a runbook for the procedure, and a Site Request with approval for the self-service ask.
THREE CASES, THREE SHAREPOINT MECHANISMS.
1. Another site from an EXISTING generic template (a team site, a helpdesk): /gallery -> Provision -> AddSiteBlueprint. SharePoint's self-service site creation. Runtime, no deploy.
2. Another RADAR (or another catalog-shaped domain: new fields, new sources): a new SPEC. What defines a radar is its feeds, its compare columns and its schedule, and those live in the spec, not in the site. SharePoint's equivalent is a solution package (.wsp) deployed to the farm. Dev-time: minutes, plus one boot. A spec-generated template is Hidden from /gallery on purpose: a site made from it by a click would have the lists but no feeds, no schedule and no reports list.
3. The PROCEDURE itself is this page (a runbook), not a workflow.
4. Self-service WITH approval (AGT.62): /gallery "Request (with approval)" or Tool.RequestSite (tool_request_site) parks an Open ApprovalRequest on Engineering/ApprovalRequests; an approver's Approve verdict on its display form builds the site, live without a restart. Hidden templates, taken names and non-alphanumeric names are refused.
THE STEPS FOR A NEW RADAR (the LLM radar, AGT.51-57, is the worked example):
1. Copy Config/Specs/LlmRadar.xml to Config/Specs/<Name>.xml. Set Site, List, Tag (the Connector Taxonomy group), Cron, and the compare Fields. List the Feeds; a JSON source gets Kind="Http" Format="Json" plus a Transform stylesheet (see wwwroot/XSLT/Intake.OpenRouterModels.xslt). Keep Views, Stages and Actions, or change them - they are data.
2. Add the markers <!-- GENERATED <Name> begin: --> and <!-- GENERATED <Name> end --> to Config/Parts.xml, then run: powershell -File tools/project-specs.ps1. The -Check switch, and FeedHarvestTests.Every_spec_regenerates..., keep it honest.
3. Declare the site in SAF-Site-Manifest.xml: <SiteBlueprint Name="<Site>" Template="SiteTemplate.<Site>"> with its own <Lists><List Name="ResearchReports" ContentType="ContentType.ResearchReport" Versioning="true"/></Lists>. git add BEFORE any boot (the manifest trap).
4. tools/spice-validate, build, boot on :5198. Run tool_harvest_feeds with the schedule's Args once. It is idempotent: a second run reports 0 new.
5. Smoke the served surface: the default view, Compare, the Funnel board, and one Send to R&D click that files <Site>/ResearchReports rnd-{itemId}.
6. Ledger row in plans/cycles.xml and a commit.
TRAPS ALREADY PAID FOR:
- A core part must never IDREF an app's part: ContentType.ResearchReport is the Studio app's, so the reports list lives on the SiteBlueprint, not in the generated template.
- The R&D workflow runs in its AppliesTo department (ResearchEnrichment, where the analyst is bound) and files into {{invokingDepartment}}. Never bind the skill per radar site.
- The schedule's Args must carry site=. Without it, Tool.HarvestFeeds fills its default list.
- A Board view keeps its GroupBy field even when ViewFields omit it. Other views drop every column not in ViewFields.
- To move rows between sites, use MoveListItems through POST /agency/apply, dry run first. Never hand-edit SQL.
source: plans/LlmRadar.md
Request a service - the intake procedureHow a new request, a research request above all, comes in and is handled: pick a service from the catalog, write a brief, the front desk routes it, the owner fulfils it, the result is filed and rated. ITIL service request management, on SharePoint lists.
THE CATALOG FIRST. What the city can do on request is the service catalog: /sites/Reception/Lists/ServiceCatalog (query_service_catalog). One row per service: what it delivers, its owner (an agency or site), what fulfils it (a Workflow or Tool, the same name as its MCP tool) and its turnaround. A request that fits no service is still welcome; if it recurs, it becomes a new catalog row, or a new division via Genesis.
THE PROCEDURE.
1. Ask: a row on /sites/Reception/Lists/Requests (or Tool.Request, the front door). Title = the question.
2. Brief, the fields that stop wasted work: ServiceRef (which service), DecisionSupported (why: the decision it feeds), RequestScope (what is in and out; for a catalog the category and market), ResearchDepth (Quick, Standard, Deep), Deliverable (what comes back, where it lands), DueDate. Only the question is required; say what is missing rather than guess it.
3. Route: the front desk (Workflow.ReceiveAndDispatch) matches the catalog first, then agency seats; nothing fits -> NeedsAgency, and Genesis proposes a division for approval. It routes; it never does the work.
4. Fulfil: the service's owner runs its ServiceFulfilment. Research answers from sources in this order: primary documents first (the datasheet, the paper, the filing), then independent tests, then customer reviews (rating, count, independence), then community pros and cons, then offers or prices. A value not found stays EMPTY and the raw text goes to the notes: never estimated.
5. File: the result lands where the Deliverable says (a list row, a ResearchReport), cited, with the request linked.
6. Close: the requester rates it (SharePoint ratings). A lesson worth keeping is proposed to Wisdom. A recurring gap becomes a catalog row.
WHY THIS SHAPE. A catalog makes routing a lookup instead of a guess. A brief with the decision it supports is how research answers the right question. A fixed source order and the silence rule are how a report stays trustworthy.
Enrol and run a worker - a seat on another machineHow a worker (a seat running outside SPICE, on another machine or in a Docker Sandbox) is declared, enrolled with only what its job needs, given jobs, and run - and the harness rules that keep a small free model honest. Where each thing is managed, SharePoint-style.
WHERE A WORKER IS MANAGED.
- Who it is: ONE row on /sites/Directory/Lists/People (Role Agent seat) - its principal (right, secret end date), Machine, AgentRuntime, ModelId, SeatStatus, AllowedTools.
- The board: /admin/seats (Central Administration) - every seat with runtime, right, last activity and open tasks.
- Its jobs: /sites/my-{seat}/Lists/Tasks. Its rights: site groups (/sites/{site}/_layouts/people, /admin/farm/permissions).
- How it runs: its COMPOSITION, SPICE.Web/Config/Compositions/{name}.xml (schema SAF-Composition.xsd).
THE COMPOSITION IS THE DECLARATION. One XML file says what runs (services: image, environment, secrets, the hosts it may reach) and, for a worker, the Seat it acts as: right, pools, site grants, MCP tools. Least privilege is data: grant only the sites and tools the job uses; allow only SPICE and the model host.
- Render it: powershell -File tools/compose.ps1 (validates against the XSD, runs every Compose.*.xslt target into dist/compositions/{name}/: a Docker Sandbox kit spec.yaml and a docker-compose.yml). -Check guards drift. A new target (Kubernetes, a VM) is one more stylesheet.
- Enrol it: powershell -File tools/enrol-seat.ps1 -Composition SPICE.Web/Config/Compositions/{name}.xml (principal onto its People row - secret to %USERPROFILE%\.spice, never printed; My Site; pools; grants; AllowedTools; runtime fields). Idempotent; -Rotate for a new secret.
- SPICE enforces it: the MCP endpoint lists and accepts only a principal's AllowedTools.
JOBS. A workflow's FallbackSeat names a seat or a POOL (a Directory site group, e.g. Research workers: the free local worker first, a stronger seat as backup). A failed run becomes a task ASSIGNED to the pool's first Available member, carrying the prompt the phase ran with, so any worker can take the phase's role.
RUN IT ON ITS HOST. Docker Desktop 4.60+: winget install Docker.sbx, then sbx run ./sandbox-{service}/ - the SPICE secret is proxy-injected for the SPICE host only and never enters the VM; the network allow-list is enforced. Fallback: docker compose up (a git-ignored .env holds the secret; the allow-list is NOT enforced). Give SPICE a LAN name (spice.lan) - sandbox allow rules are by name.
THE HARNESS RULES (tools/spice-worker, borrowed from SWE-agent, Anthropic's workflow patterns and verified tool calls):
1. finish is the only way out: complete or unknown. A reply without a tool call is nudged, not accepted.
2. complete is accepted only if a write tool really succeeded - the model's word is not evidence.
3. unknown is an answer: the task goes to review (Deferred) with the reason.
4. The last two rounds offer only the write tool and finish, and a call to a tool not offered is refused, not run (free models call them anyway); an identical call is not repeated a third time.
5. A transient 429/5xx is retried with backoff; after 3 failed attempts the task is Deferred (dead-letter), never retried forever.
MODELS. Free online, no gateway: Pollinations openai-fast (keyless, tool calling - public work only, the text goes to a third party). Local: Ollama qwen3-coder:30b-aw on 192.168.123.69 only. Measured: models that file every cell file wrong numbers; prefer the one that says not found (Wisdom: Filed is not correct).
DOCUMENTS. A worker reads a datasheet the SharePoint way: tool_add_file copies the public document into the site's Documents library (Files.Add; SPICE fetches it, public addresses only, and extracts the text page by page like an IFilter), tool_get_file reads it a page range at a time (Get-PnPFile -AsString). Grant both in the composition.
KNOWN GAP. A small free model reads the datasheet but does not carry a 40-field report to a filing in one loop (measured on openai-fast, AGT.82). Open question, backlog AGT.83: split the job into sub-tasks, or run another harness in the sandbox.
Plan in SPICE - the plan is rows, delegation is an assignmentFor every seat and the operator: where a plan lives, how work is delegated, where risks go, and who runs where. The operator's rule of 2026-09-27.
THE PLAN IS ROWS, NOT A CHAT.
- A programme is a Project on /sites/Projects/Lists/Projects (ProjectCode, Title, Notes = the operator's ask in their words).
- Its work is ProjectTasks: tasks, and subtasks under them through the Parent task column (SharePoint's ParentID on a Tasks list). Every row carries AssignedTo (a seat or a person), EstimateHours, Status (Not Started, In Progress, Completed, Waiting on someone else, Deferred), PercentComplete and a Body that says what done looks like.
- File the rows in the Decide phase, before code; close them in Retrospect (Status Completed, PercentComplete 100, the outcome under Body); file what a cycle owes as new subtasks. The operator, the seats and the daily brief read the rows; a transcript dies with its session.
RISKS AND DEFECTS ARE ISSUES.
- /sites/Projects/Lists/Issues is SharePoint's Issue Tracking list: IssueType Risk or Bug, Priority, an owner (AssignedTo), IssueStatus.
- Comments go on IssueComments, by the seat or person as themselves (Author), in their role. Never resolve a disagreement silently: write both readings in the comment.
DELEGATION IS AN ASSIGNMENT.
- Set AssignedTo on a ProjectTask to an agent seat (a Directory/People row with Role Agent seat). The platform files that seat's own task on /sites/my-<seat>/Lists/Tasks with the FULL context: the task's fields, the chain of parent tasks, the project, the seat's role and a pointer to the source row. The seat works its own list; its Status and TaskOutcome mirror back onto the plan row. A person assignee gets the assign-to mail instead.
- Tell a seat more after the fact through the task's Comments column (append-only: each save adds a stamped entry; the platform relays it onto the seat's task as a Comment: line). Order work with Predecessors (a task assigned while a predecessor is open waits, and is delegated the moment the last one completes, with their outcomes) and point at what to read first with Related Items, one reference per line - the seat opens what it needs instead of the whole phase being pasted into its Body.
- A seat may not write on another seat's My Site (seat privacy); only the platform may. Do not paste context into a seat by hand - assign the row.
- A research seat delivers files (the scratchpad, or the library), and its outcome on the row; a long message truncates.
WHO RUNS WHERE.
- A seat with a subscription (Claude Code and its subagent seats) runs where it is.
- A seat without one runs in the Docker sandbox on the LAN worker host with a Composition (Config/Compositions/<seat>.xml): a free online model, only the site groups and MCP tools its job needs, no secrets in the VM (KB.Manual.08-Workers).
WHERE THINGS ARE.
- The plan of this operating model: Project SPWAY on /sites/Projects. The client: python tools/spice.py (put Projects/ProjectTasks <key> ...; call tool_update_list_item ...). The rule for coding agents: the Decide and Improve steps of the ioodari skill.
source: Project SPWAY on /sites/Projects
Copilots - our agents, governed like documentsFor the operator and every site owner: what a copilot is here, its columns, its lifecycle from Draft to Published, the test, the site boundary, what publishing does and what is still owed. SPWAY.12c.
COPILOTS ARE OUR AGENTS, GOVERNED LIKE DOCUMENTS.
- There is no Microsoft Copilot in SPICE. "Copilots" is SharePoint's name for the library where a site keeps its agents, and each row in it is one of ours: an ActorProfile (role, instructions, tone, model, skills) with the governance SharePoint adds - owner, status, the site it may read, the audience, a risk level, when it was tested and published.
- Every site that mans agents has a Copilots library (/sites/<site>/Lists/Copilots); every seat has a personal one on its My Site (/sites/my-<seat>/Lists/Copilots), SharePoint's agents in OneDrive.
THE COLUMNS, IN THE ORDER THE FORM SHOWS THEM.
- Overview: Title, Description, Owner (a person or seat from the directory), Status.
- Behaviour: Actor role, Goal (the instructions), Backstory (the tone), Provider and Model (the model policy), Conversation starters (the questions it is offered with, one per line - the first is what the test asks).
- Knowledge and data access: Knowledge sources, one line per source as list=<ListName> access=Read - only this site's lists; another site's list is refused, the site is the security boundary.
- Permissions and actions: Skill catalog (the skills it may call) and Allowed tools.
- Governance: Risk level (Low answers from published content; Medium reads restricted lists or writes; High acts outside the site, spends or reaches people), Audience, Department (the business area the views group by), Last tested, Last published.
THE LIFECYCLE.
- Draft -> Submitted -> Published, with Disabled and Archived escapes; Archived is final. Publishing requires Last tested: an untested copilot cannot be offered. A Member publishes a tested Draft directly; a Submitted copilot needs a Manager to approve. Rule of thumb until the form enforces it: High risk goes through Submitted.
- Test: open the copilot and press Test. It asks the first conversation starter as the copilot, grounded on its knowledge sources, shows the answer on the page, records the exchange on /board/comms and stamps Last tested. No starter, no test.
- Publish: the copilot becomes an actor on the Hub (Hub/Actors, as Actor.<site>.<key>) that the engine can run and anyone may chat with (the Chat with an Agent tool); Last published is stamped. Disable or Archive removes the actor again; a re-publish brings it back.
THE VIEWS.
- All, Published, My Copilots (yours as owner), Drafts needing review (Submitted), High-risk, Disabled or archived, By business area.
WHAT IT CANNOT DO YET.
- A copilot answers from list rows placed under its prompt; it does not browse pages or call tools on its own. The guided creation flow (one step per section) and the High-risk rule on the Publish button are planned (SPWAY.12c-4); a published copilot with a runtime of its own becomes a seat (a directory row and a My Site) - that enrolment is the next row after it.
source: Project SPWAY, plans/spway/12c/design.md
The mind-map crew - ask it, use it, request from itBRAINSTORM.18: how a builder seat uses the Brainstorm mind map: ask the crew about selected nodes, suggest ideas, run a methodology on a node, and request changes to the map through the Service Catalog.
WHAT IT IS. /sites/Brainstorm is a mind map made of list items: Ideas is a Tasks-shaped list (ContentType.MindMapNode: Title, Body, Status, ParentID, Topics, ProjectRef, Order). Open it with ?view=mindmap on any list that has a ParentID column (ProjectTasks too); ?view=mm exports it as a FreeMind map and Import .mm reads one back. The mind-map crew (Agency.MapCrew) answers questions about it and works on it.
ASK THE CREW (any seat, any time). tool_chat_agent to=Agency.MapCrew input="Selected items (site=Brainstorm list=Ideas): [[node:ID]] Title ... Question: ..." - the map copilot answers on the free model, opens more only when needed (Tool.ReadNodes: a summary with path, parent and children by id, then detail=full; Tool.SearchRows across MapChat.SearchLists) and cites items as [[node:ID]]. Do not dump whole lists into the question: name the items, the copilot walks from there.
WHAT ELSE IT DOES.
- Suggest ideas: tool_suggest_ideas site=Brainstorm list=Ideas itemId=ID steer="optional direction" - five child ideas land PENDING (content approval); the operator approves or rejects them on the map. Rejected ideas are fed back as do-not-repeat.
- Run a methodology on a node: POST /sites/Brainstorm/Lists/Ideas/Item/ID/Workflows/Start?workflow=Workflow.Ioodari (or the node menu: Start workflow: IOODARI) - seven steps, each a Pending child under the node. A new methodology is a Workflow plus one EventReceiver Event="WorkflowStart"; the node menu grows by itself.
- Read and write nodes: Tool.ReadNodes, tool_publish_to_list / the list API (POST, PUT merge, DELETE) on Brainstorm/Ideas; a node written by a seat lands Pending for the operator.
REQUEST A CHANGE TO THE MAP ITSELF (a feature, a fix, a new methodology): file it like any service request (KB.Manual.07) - a row on /sites/Reception/Lists/Requests with ServiceRef=mind-map-chat or mind-map-ioodari, or a ProjectTasks row under project BRAINSTORM. The backlog is query_open_backlog project=BRAINSTORM.
THE KIT. The crew is packaged the SharePoint way, as a Feature: Feature.MapCrew binds its skills (Skill.MapResearch, Skill.Ioodari) on a site; /sites/Brainstorm activates it in its blueprint, and a new brainstorm site gets the crew by adding the same Feature. The rest of the kit: Agency.MapCrew (who answers), the actors (Actor.MapCopilot, Actor.MethodCoach), the tools (Tool.ReadNodes, Tool.SearchRows, Tool.SuggestIdeas), the method (KB.Method.Ioodari), the settings (Scope.Brainstorm, Scope.BrainstormModel) and this page.
FROM IDEA TO PROJECT (the demand funnel, Project Server's demand management). Every node has a Stage: Idea, Proposal, Project or Parked, shown as its first chip. Right-click a node, Propose as project: Tool.ProposeProject (tool_propose_project site list itemId code) parks ONE approval request on /sites/Engineering/Lists/ApprovalRequests and moves the node to Proposal. Approve it there (Add verdict, Approve) and the project lands on /sites/Projects (Status Planning) with one ProjectTask per approved child node in map order, and the node moves to Project with ProjectRef pointing at it. Delegate from there: assign a task to a seat on ProjectTasks and the platform files it on the seat's My Site. Run a Pre-mortem on the node first so the project starts with its risk list.
A BRAINSTORM'S CONTEXT (like a Claude Project). The root node of a brainstorm is its project: its notes are the instructions, Comments (append-only, who and when) the discussion, Sources (Site/List;Site/List) where the crew searches. Every workflow under it and the map chat read that context first and search only its Sources.
START FROM WHAT EXISTS. Start workflow: Benchmark similar products opens a form first (domain, goal, products you know, how many). It writes the similar products with a feature table, then proposes the features worth adopting as Pending children - approve the ones you adopt.
FORMS (InfoPath, the SPICE way). A FormTemplate part names a content type as its schema and declares Validation/ErrorCondition rules in XPath 3.1 over the answers (<myFields><Name>value</Name></myFields>, the rule's field as context item), checked by the platform's Saxon engine as you type and again on submit. A Workflow with InitiationForm opens it before it starts; the answers reach the phases as the task's FORM ANSWERS and as {{init.Name}} in tool arguments.
ON THE MAP. Drag a box on empty canvas to select every node it touches (Shift adds). A node shows its running workflow as a chip (Pre-mortem 2/3, done, error) from the Workflow History list; the map refreshes while one runs. Ask the chat to add things ("add all X under Y"): the copilot adds them in one call (Tool.AddNodes), Pending for your approval.
SITES, THE SHAREPOINT WAY. SharePoint's template catalogue is data: Config/TEMPLATE/1033/XML/WEBTEMP.XML (the 72 SharePoint 2016 templates) and WEBTEMPFAB40.XML (the Fab 40), read as-is. A template SPICE builds carries its key (Team Site = STS#0); the rest are listed as catalogue-only. Agents (the Site builder in the map crew, or any seat with Skill.SiteProvisioning) pick a template with Tool.ListSiteTemplates, request the site with Tool.RequestSite (a key such as STS#0 works), and request a feature on a site (Tool.RequestFeatureActivation) or stapled to a template (Tool.RequestFeatureStapling - a stapler feature with SharePoint's FeatureSiteTemplateAssociation). Every request waits for approval on /sites/Engineering/Lists/ApprovalRequests; a site created from a template gets its template's and stapled features at once.
FIND YOUR WAY. Every site and list says in one line what it is for. Site Contents (/sites/X/Lists) is the site's table of contents (?format=xml for agents, or Tool.SiteContents); each list links About this list (what it holds, what runs on it, who may use it).
METHODS. A method is data: a Workflow of Phases, each filing one numbered Pending child under the node, started by hand (an EventReceiver with Event WorkflowStart). Two ship: IOODARI (seven steps) and Pre-mortem (Failure, Causes, Mitigate - Gary Klein). Add one by declaring a KB.Method.X article, its phases, a workflow and a WorkflowStart receiver - or have the parts builders do it through an approved delta (AddPhase, AddWorkflow, AddEventReceiver).
INHERITED WORKFLOWS. An EventReceiver on a content type also fires for every type that inherits from it (SharePoint's association pushdown): a WorkflowStart on ContentType.Task reaches Mind Map Nodes too. Inherit="false" keeps one to its exact type.
VIEWS. The map is a declared view (View Type="MindMap" Url="Map.aspx") and the default on Ideas and AgentMap; AllItems.aspx is the table. ?view=mindmap still works on any list with a ParentID.
THE MAPS. Ideas is the operator's map; AgentMap is the agent landscape - every agency, its members, their skills and tools - generated from the part spine by tools/map-agents.py (re-run it after agents change). Open either with ?view=mindmap.
FOR A CLAUDE CODE SEAT. The skill spice-mindmap (.claude/skills/spice-mindmap, published to my-claude-code/AgentAssets Skills/spice-mindmap/SKILL.md) holds the commands; every capability above is also an MCP tool on /mcp/jsonrpc (tool_read_nodes, tool_search_rows, tool_suggest_ideas, tool_chat_agent, workflow_ioodari).
RULES. Proposals from a model are never live until the operator approves them. Cite only ids you read. Methodology and suggestion runs are pinned to the free model (Scope.BrainstormModel).
Reception - what an arriving agent is toldThe briefing served in the MCP initialize handshake, in the protocol's own instructions field. This is the first and often only thing a peer agent reads about this platform, so it is DATA and not a C# literal: change the welcome by editing this part.
WELCOME. This is SPICE, a SharePoint-shaped content and agent platform. If you know SharePoint you already know your way around here: sites, lists, content types, views, tasks with AssignedTo. Nothing here needs a bespoke vocabulary explained to you. START HERE, NOT WITH THE TOOL LIST. YOUR FIRST TWO CALLS: resources/list returns every skill and article by NAME and one-line description - the index, never the bodies. Then resources/read spice://parts/Skill.NavigateTheSpine, the one skill on how to find your way here, and read any other resource only when its one-line description says you need it. That is a SharePoint site's own progressive disclosure: Site Contents, then one list, then one item. This server advertises around a hundred tools and reading them all is not orientation, it is drowning. Four tools do almost everything you will want. tool_send_mail delivers a message to the operator's in-city inbox and is how you reach a human or another agent here - give it to, from, subject and body, and a key if you want a repeat send to overwrite rather than pile up. tool_search finds things by text when you do not know the name. tool_xquery (needs the Write right, see WHO YOU ARE HERE) runs one XPath or XQuery over the whole declared spine and is the cheapest way to answer "what exists" - try count(//Skill), or for $s in //Skill return $s/@Id for names only. tool_publish_to_list writes a typed row into a list. THE LADDER. Ask for the shape before the detail: GET /about returns counts by kind, one XQuery returns the names of one kind, a predicate narrows it to a slice, and only then do you fetch one part in full at /agency/parts/by-id/{id}. Never descend a level you were not sent to by the level above, and never grep what one XPath answers. WHO YOU ARE HERE. Every tools/call runs as a principal, the SharePoint app-principal way. Without credentials you are anonymous and hold the Read right: you can list and read, not write, and the tool and resource lists show only what Read may call - SharePoint security trimming. A site or list can also break inheritance the SharePoint way (HasUniqueRoleAssignments): every agent seat's My Site, /sites/my-{seat}, is private to that seat. There the site home and pages, the list pages, the list API, CAML list queries such as query_my_memory, the list-write tools, and list web parts and cross-site roll-ups on other sites' pages give you nothing and refuse writes unless you are in its Owners group. Not yet trimmed that way, so do not rely on them to hide anything: search, tool_xquery, the /agency query routes, and - for a list that breaks inheritance inside an open site - that site's recycle bin. To do more, ask the operator to register you (AppRegNew): you receive a Client Id and a Client Secret ONCE, and your row in /sites/Directory/Lists/People carries the AppPermissionRequest Right you were granted - Read, Write, Manage or FullControl. Send the secret on every call as the HTTP header Authorization: Bearer your-secret. Each tool declares the right it needs; a call above yours is refused with a message naming the right it needs. That People row IS you: a task AssignedTo it is yours. WHAT TO DO IF YOU ARE HERE TO HAND US WORK. Send it with tool_send_mail. It lands as a row an operator reads at /sites/Hub/Lists/Inbox. Put the ask in the subject, the detail and the reason in the body, and say plainly what you expect back - an unreported handoff looks abandoned from both ends. Do not inline a secret or a credential in the text. WHAT WE CANNOT DO YET, stated so you do not wait on it: we do not implement the A2A task lifecycle, so there is no message/send and no task polling; invocation is this JSON-RPC endpoint. We have no per-agent private memory. Notification works the SharePoint way: a list that declares EnableAssignToEmail tells whoever a new or re-assigned item is AssignedTo, as a row in /sites/Hub/Lists/Inbox whose To column names them - filter the inbox by To for your own messages; an Alert declared on a list tells its subscriber of every Add or Modify. HOUSE RULES. A tool that fails tells you why rather than returning something plausible, so read the error. If a tool declines because of an unresolved configuration placeholder, that is deliberate: an integration here stays inert until an operator enables it.
source: SPICE.Web/Controllers/McpController.cs
Pre-trained competence - why this platform is SharePoint-shapedThe operator's reason for SharePoint fidelity, stated as economics rather than taste: every model is already trained on the SharePoint vocabulary, so a faithful part needs no teaching while every divergence is a bill charged on every future prompt. Includes the both-ways test - where fidelity would ADD a teaching bill, refuse it.
PRE-TRAINED COMPETENCE is the reason this platform is modelled on SharePoint on-prem, and it is an economic argument, not an aesthetic one. Two decades of SharePoint schema, MSDN documentation, elements.xml samples and StackOverflow answers sit in every frontier model's weights. So a part declared in the REAL SharePoint vocabulary needs NO TEACHING: no few-shot examples in the prompt, no schema pasted into the briefing, no closed-vocabulary block, no correction loop when the model invents an attribute. It writes View BaseViewID Type Query correctly the first time because it has written it ten thousand times. That competence is already paid for, it arrived free, and it is the one asset on this project that grows without us. INVERT IT AND THE COST BECOMES VISIBLE. Every divergence from the real schema is a TEACHING BILL, and it is charged on every future prompt, forever. A SPICE-only attribute must be explained in the briefing, defended by a validation gate, and corrected each time the model reaches for the SharePoint name it actually knows. A clever bespoke abstraction can therefore be strictly WORSE than a clunkier faithful one: ours must be taught to every agent, every session, for the life of the system. THE RULE. Prefer the SharePoint shape ALWAYS - not for new work only, not when convenient. Before naming anything, ask 'would a model already know this name?' before asking 'is this elegant?'. Ask it of every FIELD, not just the part kind: on 2026-09-22 a task content type was declared with CrewSeat, CrewBrief, CrewFindings and CrewStatus when SharePoint's Task type (0x0108) already had AssignedTo, Status, Priority and Body - and three of those four already existed in this spine. Correct kind, invented fields. WHILE WE ARE IN DEVELOPMENT, 'it is already in use' is NOT a reason to keep a divergence. No external consumer depends on our bespoke choices, so changing one costs only the edit, while keeping it is charged forever. That asymmetry exists only before production - spend it now. IT CUTS BOTH WAYS, which is what makes it a real tool rather than a slogan. Do NOT borrow where we are ahead or where fidelity would ADD a bill: the 0x0100 hex content-type lineage is opaque and must be explained, while a plain IDREF parent is self-evident; ReceiverAssembly and ReceiverClass would reintroduce compiled binding where a Skill or Workflow IDREF is data; SafeControl is what a DI registration already is; workflow association forms are ceremony for a human step this platform does not have. Fidelity is the default, not the dogma. THE TEST FOR A GAP: rank it by how much teaching its absence forces, not only by what an operator would notice. And before calling a capability done, check it is reachable by DECLARATION ALONE - if using it needs a C# edit first, the vocabulary is not shipped yet.
source: plans/AgencyArchitecture.md