--- title: Be Civic — Cowork Plugin Specification (formerly v1-spec; renamed 2026-05-18 ahead of multi-harness expansion) type: spec status: draft date: 2026-05-19 parent_spec: ./README.md parent_amendments: - ../docs/amendments/applied/2026-05-11-amendment-c1-observation-taxonomy.md - ../docs/amendments/applied/2026-05-11-amendment-c4-consumer-runtime.md - ../docs/amendments/applied/2026-05-11-amendment-c7-consumer-state.md - ../docs/amendments/applied/2026-05-11-amendment-schemas-and-agents-mdx.md - ./amendment-proposals/2026-05-17-plugin-as-bootstrap.md - ./amendment-proposals/2026-05-18-cowork-plugin-onboarding.md - ./amendment-proposals/archive/2026-05-19-dossier-rebuild.md forward_dependencies: - ./amendment-proposals/2026-05-18-onboarding-rebuild.md tags: ["be-civic", "bc-internal", "v1", "mvp", "cowork", "plugin"] --- # Be Civic — Cowork Plugin Specification **What this document is.** The scope contract for the Be Civic **Cowork plugin** — the first concrete harness Be Civic ships. The Cowork plugin is the canonical onboarding path per architecture.md §3 principle 13 (plugin-as-bootstrap, 2026-05-17 amendment). This document covers acceptance criteria, plugin contents, Cowork-host-specific onboarding flow, alpha-operational consent posture, filesystem layout under the Cowork host, and build sequence. **What this document is NOT.** The architecture spec. Universal architecture lives in the harness-agnostic sub-spec docs (start at [README.md](README.md)). The harness-agnostic onboarding flow (gate classification, confirmation gate, branded form delivery, folder-mount-after-submit) lives in architecture.md §24.3 / §24.6. This document pins each universal step to its Cowork primitive (`mcp__visualize__show_widget`, `sendPrompt`, `mcp__cowork__request_cowork_directory`) and adds Cowork-bundle-specific contents and on-disk file layout. **Multi-harness posture.** As of 2026-05-18 the previous `v1-spec.md` was renamed `cowork-plugin.md` ahead of multi-harness expansion. Sibling harness specs (ChatGPT app, etc.) will get their own `.md` documents when those surfaces are locked. Procedure canonicals (`bc-docs/skills//canonical.md`) and the harness-agnostic flow are deliberately shared; the Cowork-specific surface mechanics live here. **Tag convention.** Throughout this document, subsections carry an implicit `[Cowork]` (durable Cowork-harness spec content) or `[Alpha-operational]` (alpha-and-beta operational reality, revisited at post-alpha cutover) classification. Where ambiguous, the relevant tag is noted inline. **Procedure scope at v1.** A single procedure: **Belgian nationality declaration via art. 12bis** (5-year residence path), filed at the commune État Civil. Three legalisation sub-skills cover origin-country routing (`apostille-foreign-document-hague`, `consular-legalisation-foreign-document`, `eu-2016-1191-multilingual-form`); a meta-skill (`meta-no-skill-fallback`) handles procedures outside the corpus. This is the worked example. All other Belgian admin procedures are out of v1 scope. **Customer scope.** A single tester: friend referred 2026-05-11. Adult, EU or non-EU national, 5+ years registered residence in Belgium, considering nationality declaration. Pays €20/month for Claude Desktop with Cowork tab. Comfortable installing a plugin and pointing the agent at a folder she chose; not a developer. ## 1. Acceptance criteria v1 is "shipped" when **all** of the following are true for the friend tester: 1. She has installed the Be Civic plugin from the Cowork Plugins directory in Claude Desktop (or — per §1.1 fallback below — from the marketplace-by-GitHub-URL path or the zip-upload fallback). The plugin install places the harness skill, peer skills, drafter sub-agents, starter state templates, and schemas under the Cowork plugin runtime automatically; **no zip download or manual folder selection is required at install time**. (Folder selection happens later during onboarding, via `mcp__cowork__request_cowork_directory`, per §3.3.) 2. She has connected `mcp.becivic.be` via Settings > Integrations > MCP (optional — v1 delivers full guidance with MCP absent via the §6 fallback chain). 3. She has opened a session in the Cowork tab. The `be-civic` gate skill auto-activated on her opener and routed her through `bc-onboarding`. 4. The harness has elicited her routing context via the branded onboarding form (per §3.2) and written it to `/BeCivic/profile.json` (per §2.9 layout). The form populated the V1 profile fields per `schemas/profile.schema.json`: `region`, `commune_nis5`, `administration_language`, `conversation_language` (free text per the universal-amendment D27), `civic_status`, `nationality_status`, `residency_status`, plus the new V1 fields `has_id_card` (per D23; renamed from `has_eID` — depends on the universal proposal landing the rename in the live schema), `browser_driving_preference` (per D8), and the `consent` block with `alpha_bundle` / `signed_at` / `version` (per D28; see §3.8). The harness never asked for her name, date of birth, document numbers, NISS, or full address. The form rendered via `mcp__visualize__show_widget` with HTML returned from `mcp__becivic__read_skill --with_form` (per protocol.md §23.2; depends on the universal proposal landing the `with_form` parameter on the wire) with pre-population from her opener (per D33); on MCP failure, the plugin's static fallback HTML for her locale rendered instead (per §3.2 fallback paths). 5. The harness has produced a situated nationality-application guidance document — citing the statutory hook (Code de la nationalité belge, art. 12bis), listing the required documents for her commune and language, and ending with a "verify with your commune" checklist. 6. The harness has resumed in a second session and correctly identified her active procedure (`active_procedures: ["nationality-application"]`) without re-asking the routing questions. The Cowork-host returning-user detection per §3 fired the mini header (D54) at session start. 7. At least one concern has been submitted from the session via the MCP `mcp__becivic__submit_concern` tool — or HTTP fallback to `POST /api/concerns` if MCP was not configured — and is visible in the Be Civic staging surface. Submission was gated on `profile.consent.alpha_bundle: true` per §3.8. 8. She can delete `/BeCivic/` (via her OS file manager) and the next session starts fresh with no residual state. Plugin uninstall via Cowork's plugin manager is also supported and produces the same fresh-start behaviour. The harness MUST NOT prevent or create friction around deletion; deletion is the user's unilateral act per architecture.md §3 principle 11. The harness MUST NOT write state outside `/BeCivic/` or `${CLAUDE_PLUGIN_ROOT}` (the plugin's read-only / writable plugin-data location). 9. The harness called `mcp__becivic__get_graph` (or `GET /api/skill-graph` if no MCP) at session start, received the v1 graph (nationality target + three legalisation sub-skills + meta-skill), and routed her request through it. When her origin-country routing requires a legalisation sub-skill (apostille / consular-legalisation / EU 2016/1191), the harness loads the appropriate sub-skill via the `requires` edge without asking her to re-route manually. 10. The friend's conversation language was detected and offered as a pre-fill in the form's `conversation_language` field; her form rendered in the V1 locale matching her UI language (one of EN, FR, NL, DE, AR, UK per D35). If her conversation language is none of those, the form rendered in English with an in-chat nudge in her language (per G24 and §3.2 locale-fallback rule). Acceptance criterion 5 is the success signal: the friend produces a real document she can take to her commune. Criteria 1–4 and 6–10 verify the protocol contract. ### 1.1 Install path fallbacks The plugin supports three install paths, in preference order: 1. **Cowork Plugins directory** — when the Be Civic plugin is listed on the official Anthropic plugin registry, `Customize → Browse plugins → Anthropic`. Not yet available pre-launch. 2. **Personal marketplace from GitHub** — `Customize → Browse plugins → Personal → + → Add marketplace from GitHub`, then paste the plugin repo URL. Auto-updates on every push. This is the v1 ship path. 3. **Zip-upload fallback** — `Customize → My Uploads`, upload a release zip from the plugin repo's Releases page. For testers behind proxies or network restrictions that block GitHub. For Claude Code CLI: `/plugin marketplace add ` then `/plugin install be-civic`. The CLI install path is supported for development dogfooding; it is not the customer-facing v1 surface. ## 2. In scope (build this) ### 2.1 Plugin bundle contents The Cowork plugin bundle is the canonical delivery artefact. File layout: ``` be-civic-plugin/ ├── .claude-plugin/ │ ├── plugin.json # plugin manifest (name, version, description, author) │ └── marketplace.json # marketplace manifest (for personal marketplace install) ├── CLAUDE.md # OMITTED at plugin root — the harness CLAUDE.md is one-per-BeCivic-root, │ # written by bc-onboarding into /BeCivic/CLAUDE.md. │ # ONE shared-root copy services every procedure under that root (§2.9). │ # Source template lives at skills/bc-onboarding/references/harness-CLAUDE.md. ├── README.md # operator-facing repo readme; install instructions, repo status ├── .mcp.json # MCP server registration (becivic at https://mcp.becivic.be/mcp) ├── skills/ │ ├── be-civic/ # gate skill — checks for project folder, routes to bc-onboarding if absent │ │ ├── SKILL.md │ │ └── references/ │ │ └── intro-header.html # branded intro card for mid-session pickup (D54 mini header) │ ├── bc-onboarding/ # first-contact onboarding skill (owns first-contact only per D34) │ │ ├── SKILL.md │ │ └── references/ │ │ ├── onboarding.html # branded HTML widget (Pattern B; rendered via mcp__visualize__show_widget) │ │ ├── harness-CLAUDE.md # template written into /BeCivic// at folder-mount │ │ ├── onboarding.en.html # static section-1-only fallback per D44 (forward commitment — see §C reconciliation doc) │ │ ├── onboarding.fr.html # forward commitment │ │ ├── onboarding.nl.html # forward commitment │ │ ├── onboarding.de.html # forward commitment │ │ ├── onboarding.ar.html # forward commitment — RTL │ │ ├── onboarding.uk.html # forward commitment │ │ └── project-init/ # templates copied into /BeCivic// at mount │ │ ├── profile.json # starter state — all routing fields null │ │ └── MEMORY.md # empty narrative-memory index │ ├── bc-discovery/ # zero-match routing — drives to meta-no-skill-fallback or invites a skill draft │ │ └── SKILL.md │ ├── bc-document-handler/ # document intake, scrub-layer-1 invocation, document-content-discard rule │ │ └── SKILL.md │ ├── bc-path-traversal/ # walks tags, honours source priority and fallback_only │ │ └── SKILL.md │ ├── bc-session-close/ # session-end roll-up: review observations, submit, ack │ │ └── SKILL.md │ └── bc-dossier-compilation/ # dossier assembly across procedure lifecycle (initial/refresh/final modes) │ ├── SKILL.md │ └── templates/ # HTML templates: cover, checklist, divider, placeholder, filled forms ├── scripts/ # plugin-side Python (preamble, scrub, dossier renderer module) │ ├── preamble.py │ ├── scrub-layer1.py │ ├── ... │ └── be_civic_dossier/ # dossier renderer module — imported by user's render.py │ ├── __init__.py │ ├── dossier.py # Dossier container class │ └── layouts/ # 6 presentation-class transformers ├── vendor/ # vendored pure-Python deps — no pip install required │ ├── fpdf2/ # new PDF page generation │ ├── pypdf/ # PDF merge + rotate + watermark overlay │ ├── fonts/ # bundled fonts (Inter, Source Sans Pro, Noto Sans Arabic, Noto Sans Cyrillic) │ └── UPGRADING.md # vendor library upgrade procedure ├── agents/ # subagents spawned by bc-session-close for heavy authoring │ ├── bc-path-drafter.md # drafts new path entries from session research-notes │ └── bc-skill-drafter.md # drafts new skills from end-to-end session walkthroughs ├── schemas/ │ ├── profile.schema.json # for harness self-validation (V1 schema) │ └── observation.v3.schema.json # legacy observation envelope; superseded by per-type concern/amendment/draft schemas ├── data/ │ ├── scrub-rules.json # local Layer-1 regex scrub rules; refreshed at session start when reachable │ ├── privacy-attachment.md # alpha-specific terms (D49); forward commitment — see §C reconciliation doc │ ├── privacy-snippet.md # canonical privacy answer for meta-question shape (D47); forward commitment │ └── mini-header-strings.md # 8-10 rotating call-out variants (D13); forward commitment ├── scripts/ │ ├── preamble.py # session-start orchestrator: SESSION_ID, USER_DATA_DIR, PENDING_STATE, capability flags │ ├── scrub-layer1.py # local regex scrub before any submission │ ├── scan-orphan-buffers.py # scans for stranded observation-buffer files from prior sessions │ ├── scan-pending-state.py # detects pending submissions awaiting user review │ └── detect-browser-capability.py # probes for Chrome / Chrome MCP / Be Civic MCP at session start ├── hooks/ # consent-flow hook templates (post-alpha) — ships empty in v1 alpha │ └── .gitkeep ├── .github/workflows/ │ └── plugin-validate.yml # CI: schema validation, plugin.json shape, SKILL.md frontmatter strictness ├── .gitignore └── LICENSE # MIT ``` **Key plugin-format facts.** - `${CLAUDE_PLUGIN_ROOT}` is set by the Cowork plugin runtime at session start and resolves to the plugin's installed (read-only) folder root. `${CLAUDE_PLUGIN_DATA}` is the writable plugin-data location surviving plugin updates; `preamble.py` falls back to `${CLAUDE_PLUGIN_ROOT}` (script-parent) when both env vars are absent (Cowork-Project legacy mode). - The harness `CLAUDE.md` is NOT at the plugin root. It lives at `skills/bc-onboarding/references/harness-CLAUDE.md` as a template, and gets copied to **`/BeCivic/CLAUDE.md`** (the shared BeCivic root — one CLAUDE.md services every procedure under it, per §2.9) at folder-mount time per §3.3. This is because Cowork's `CLAUDE.md` auto-load convention walks ancestors and picks up the BeCivic-root file when the user opens any procedure subfolder. - The plugin does **not** ship a local snapshot of procedure skill bodies. Procedure content (nationality, apostille, etc.) is MCP-delivered live from `mcp.becivic.be` (or HTTPS / WebFetch fallback per §6 of the harness CLAUDE.md). The plugin ships only **meta-skills** (be-civic gate, bc-onboarding, bc-discovery, bc-document-handler, bc-path-traversal, bc-session-close, bc-dossier-compilation) — the agentic behaviour layer. The procedure layer is served from becivic.be. - Forward commitments (the six locale fallback HTML files, `privacy-attachment.md`, `privacy-snippet.md`, `mini-header-strings.md`) are scheduled deliverables tracked in §5 build sequence. They are not yet present on disk; the reconciliation doc tracks them under "Specced but not built." ### 2.2 MCP server + api Worker additions Existing `mcp.becivic.be` already exposes the per-type submission tools, `find_skill`, `read_skill`, `get_graph`, and path-directory tools. v1 adds the following surfaces: **1. Bootstrap (MCP-only):** - **`mcp__becivic__bootstrap()`** — returns a one-shot orientation payload: the current `/agents` boot-loader text, the manifest, and the URL for the latest plugin install link. Called by agents on first contact when they want a deterministic alternative to `WebFetch becivic.be/agents`. **2. Skill-graph (MCP + HTTP parity):** Per §24.2 (see architecture.md; revised 2026-05-11 PM), the skill routing graph is served live from D1, not as a static file. v1 ships both surfaces: - **`mcp__becivic__get_graph(filters?)`** — MCP tool. Filterable by `applies_to`, `status`, `customer_locale`, `profile_match`. Returns nodes + edges per the response-shape schema in the schemas amendment. - **`GET https://becivic.be/api/skill-graph`** — HTTP parity endpoint. Same JSON response. Filters as query-string parameters. Required for harnesses without MCP and for the HTTPS fallback rung. Both surfaces share the same D1 query and serializer. Edge caching: `Cache-Control: public, max-age=60, s-maxage=60`. In v1 the graph has five nodes — `nationality-application` (target procedure, status `beta` at ship), `apostille-foreign-document-hague`, `consular-legalisation-foreign-document`, `eu-2016-1191-multilingual-form` (status `alpha`), and `meta-no-skill-fallback` (status `beta`). Edges encode `requires` relationships from `nationality-application` to each of the three sub-skills. **3. Extended `read_skill` with onboarding form (forward dependency on universal proposal):** The universal onboarding-rebuild proposal extends `read_skill` with `with_form`, `app`, `locale`, `mode`, `pre_selected`, and `profile_snapshot` parameters, and adds a sibling `get_onboarding_form` tool. Both return server-rendered branded HTML for the Cowork-host `mcp__visualize__show_widget` widget surface. **This is a forward commitment — depends on the 2026-05-18-onboarding-rebuild.md universal proposal landing.** Until it lands, v1 falls back to the static `onboarding.html` widget already in the plugin bundle (§3.2 details). **4. Cowork bindings for `row_list` form inputs with deferred-capture modes (W25, 2026-05-19):** The `row_list` form input type (defined in schemas.md "Form-input types") supports three capture modes; the type and its sentinel-payload contract are catalogue-backend concerns spec'd in schemas.md + protocol.md §23.2. Cowork's host-specific bindings: - **Widget rendering.** All three modes render via `mcp__visualize__show_widget` — the standard Cowork host primitive already used by the V1 branded onboarding form. - **Folder-drop mode** uses the Cowork-mounted project folder (via `mcp__cowork__request_cowork_directory` per §3.3). The path shown to the user resolves to `/BeCivic//inputs//`. The agent reads dropped images from this path via the workspace bash / file tools after the user signals completion. - **Post-submit hydration** is owned by `bc-onboarding` (per its peer-skill paragraph in §2.3): when the form submit returns `__status: "pending"` on a `row_list` field, bc-onboarding's Step 7.1 probing reads the sentinel, runs the mode-appropriate hydration (poll folder + vision-extract for `folder_drop`; chat elicitation for `chat`), and re-renders the same widget pre-populated for user confirmation before writing the final value to the target store. Locked design: [`../docs/agent-ux/row-list-input-type-design.md`](../docs/agent-ux/row-list-input-type-design.md). **D1 schema migration:** the skills catalogue table gains columns `applies_to` (enum), `tags` (JSON array), `prerequisites` (JSON array of skill_ids), `related` (JSON array of skill_ids), `profile_requirements` (JSON array of profile.json field names). Backfill: one row each for the five v1 skills. Migration via `bc-docs/migrations/-add-skill-graph-columns.sql`. ### 2.3 Harness skill (`be-civic` gate + `bc-onboarding` peer + harness CLAUDE.md) The two-layer runtime defined in §24.1 (see architecture.md), Cowork-plugin-shape: - **`skills/be-civic/SKILL.md`** is the gate. Its only job is to detect whether the current cwd is inside a Be Civic project folder (marker file at `.be-civic/marker`) and route accordingly. If yes → confirm and exit (CLAUDE.md inside the project is already driving). If no and the user has an admin query → invoke `bc-onboarding` in `new-project` mode. If no and no specific query → softer opening, offer to set up. - **`skills/bc-onboarding/SKILL.md`** owns first-contact only (per D34). Two modes: `new-project` (full setup-and-onboard sequence in this conversation, ending with handover to "re-open this folder in a new chat") and `first-contact` (running inside an existing project folder where CLAUDE.md detected `PROFILE_JSON: absent`). (A prior `migrate-from-v1` mode was stripped 2026-05-18 — no users exist to migrate.) - **`skills/bc-onboarding/references/harness-CLAUDE.md`** is the harness body — Iron Law, situation-assessment-first, decision tree, profile/memory rules, MCP/HTTPS/WebFetch fallback chain, inline tag handling (`` / `` / `` / `` / `` / ``), observation handling, document handling, path traversal entry, dossier compilation entry, session close. This file is copied to **`/BeCivic/CLAUDE.md`** (a single shared-root copy per §2.9) at folder-mount time so Cowork loads it as Project Instructions for any session opened from that BeCivic root or any procedure subfolder under it. - **Peer skills** (`bc-discovery`, `bc-document-handler`, `bc-path-traversal`, `bc-session-close`, `bc-dossier-compilation`) — each is a focused mode the harness invokes via the Skill-tool route. They live under the plugin bundle so they're loadable on any Be Civic project folder without per-project install. Per-skill purpose (one paragraph each): - **`bc-discovery`** — handles the no-verified-skill and no-verified-path cases. Has two modes: `skill` mode fires on graph zero-match for the customer's intent (or when `bc-path-traversal` returns `unknown-skill-fallback`); `path` mode fires when `bc-path-traversal` returns a structured miss signal (`unknown-path-id` or `all-sources-failed-with-alternative`). Frames the beat as "discovery mode" with the customer (not "no-skill fallback" — that's internal language), walks them through the procedure with research-as-we-go discipline, applies source-quality rules (Belgian statute / federal regulation / regional decree as citation-grade), and produces a durable `research-notes-*.md` file that the drafter sub-agents consume at session close. Helps today's customer through their procedure while building the artefact the next customer with the same intent will hit verified. - **`bc-document-handler`** — handles document presentation at the moment it happens (paste, upload, attachment, photo, or verbatim field description). Applies the always-on rules from harness CLAUDE.md §7 — take only the routing fields the active procedure needs, archive the original to the customer's machine under `documents//`, never write document bodies to routing stores (`profile.json` / `MEMORY.md`), maintain a cross-procedure index so subsequent procedures know which documents are already present. Inline by design: runs the per-drop extract-archive-confirm dialogue and abort handling without context-switching back to the procedure skill for every document. - **`bc-path-traversal`** — owns the §6.12 Path Directory traversal contract for any inline `` tag in a procedure body, any frontmatter `requires_paths:` entry reached at filing or document step, or any customer-initiated path request. Loads the catalogue, applies the three invariants (source-priority order, eligibility-predicate filtering against profile, `fallback_only` discipline with `offline` always last), executes per-source attempts with consent gates and handoff text, files a `validation` submission per attempt (`confirm` on success, `reject` with rationale on failure), and degrades to bc-discovery in `path` mode on exhaustion. Honours `browser_driving_preference` for Chrome MCP handoff vs AskUserQuestion vs markdown-link routing. - **`bc-session-close`** — handles end-of-session rollup. Two invocations: **full close** (procedure terminal step, explicit customer close, session timeout) runs the 9-step sequence — summary, save state, per-item observation review with the customer using customer-facing language ("list" / "notes", never "buffer"), drafter handoff for ready research-notes (auto-spawns `bc-path-drafter` and `bc-skill-drafter` sub-agents), contributions double-filtered, submission, next-time framing, cleanup, goodbye; **resume-submit** (invoked from the pending-state surface at session open) skips review/cleanup beats and jumps to submission for items the customer chose "handle now" on a deferred item from a prior session. Each per-item review respects the 24-hour cancel window contract. - **`bc-dossier-compilation`** — handles dossier assembly across the lifecycle of an `application_dossier`-class procedure. Three modes: `initial` (fires after `bc-document-handler` archives the first document for the procedure, producing an early-stage dossier with placeholders for outstanding items so the user sees the artefact taking shape), `refresh` (fires after each subsequent document arrives, replacing the relevant placeholder with the real document), and `final` (fires at the procedure's terminal step via an inline `` tag, producing the version the user prints and files). Produces a **fully-bound A4 PDF** containing: cover page, checklist table, "bring originals" callout, agent-authored officer notes, every gathered document rendered through one of six standardised presentation classes (`id-card`, `full-page-cert`, `multi-page-doc`, `fee-receipt`, `filled-form`, `placeholder`), and filled official forms at the end. Items where the procedure canonical's required-documents row marks the form as anything other than `Printout acceptable` receive a diagonal watermark in the user's `conversation_language` on every page (six locales: en/fr/nl/de/ar/uk). The renderer is **vendored pure-Python** (`fpdf2` for new pages, `pypdf` for merging + watermark overlays); no system dependencies, no `pip install` at plugin-install time. The agent writes a `render.py` script in the user's project folder at `/dossier/render.py` and iterates on it as documents arrive — the user can also edit the script directly. Agent-tooling sub-skill: produces an artefact rather than running a Belgian admin process; Be Civic does not stage or store the dossier (it intentionally carries identity-shaped data, which stays in the user's local folder); the renderer runs locally on the customer's machine. Locked design: [`../docs/agent-ux/dossier-rebuild-design.md`](../docs/agent-ux/dossier-rebuild-design.md) (W25, 2026-05-19). - **Drafter sub-agents** (`bc-path-drafter`, `bc-skill-drafter`) — spawned by `bc-session-close` to author amendments and new entries from session research-notes. Defined as agent files under `agents/`. Per-agent purpose: - **`bc-path-drafter`** — drafts new Be Civic path entries (single-outcome routes like portal flows, commune deeplinks, or single forms), or amendments to existing paths, from session research-notes. Spawned by `bc-session-close`, OR by `bc-skill-drafter` when content turns out path-shaped rather than skill-shaped. Reads `/memory/research-notes-.md` plus any existing entry from `paths/index.json` (for amendments); emits a structured payload per harness-spec §H.6. Model routing: `amendment` → sonnet (mechanical edit); `proposal` → opus (judgment-grade for new entries). - **`bc-skill-drafter`** — drafts new Be Civic procedure skills, or amendments to existing skills, from session research-notes. Spawned by `bc-session-close` when a customer's experience reveals a procedure the catalogue lacks or should change. Reads `/memory/research-notes-.md` plus any cited canonicals; emits a structured payload per harness-spec §H.6 (drafter-subagent output contract). Model routing: `amendment` → sonnet (mechanical edit); `proposal` → opus (judgment-grade for spec §15 compliance). Detects path-shaped content and routes to `bc-path-drafter` when appropriate. - **Three-step fallback chain for data fetch and submission** (per architecture.md §24.4.1; see harness-CLAUDE.md §6): 1. MCP tool call if available 2. HTTPS endpoint at `becivic.be/api/...` if MCP unreachable 3. WebFetch of the canonical content from `becivic.be` if HTTP API unreachable - **Observation submission** follows the same chain: `mcp__becivic__submit_concern` → `POST /api/concerns` → buffer to disk under `/.be-civic/sessions//observations-buffer.jsonl`. ### 2.4 Procedure skills (MCP-delivered, NOT plugin-bundled) The target procedure exists in the public corpus at `bc-docs/skills/nationality-application/canonical.md` (currently `status: alpha`). Its `requires:` frontmatter names three legalisation sub-skills, one of which applies per customer based on their origin country's treaty status: | Skill | Selects when | v1 status | |---|---|---| | `nationality-application` | (target procedure) | promote `alpha` → `beta` for v1 ship | | `apostille-foreign-document-hague` | origin country is a Hague Apostille Convention signatory | `alpha` | | `consular-legalisation-foreign-document` | origin country has no treaty relationship | `alpha` | | `eu-2016-1191-multilingual-form` | origin country is an EU member state | `alpha` | | `meta-no-skill-fallback` | zero-match routing per §24.8 (see architecture.md) | promote to `beta` for v1 ship | These five skills are served live from `mcp.becivic.be` (or HTTPS fallback). They are NOT shipped in the plugin bundle — the harness fetches them at runtime via `mcp__becivic__read_skill`. This keeps procedure content updates flowing without plugin re-installs. For v1: - **All five skills** must be reviewed for skill body discipline (§15.8 (see skills.md): no implementation paths, no operator references, no design rationale, no dogfooding notes), customer readability (§15.8 invariants 7 and 8: glosses for admin/legal jargon on first use; legislation references in prose form, not parenthetical citations), and the new invariant 11 on positioning copy (Be Civic is a tool the user's agent uses, not an agent itself — depends on the universal proposal landing). - The **nationality skill** must cover at minimum: eligibility (5-year continuous residence; permitted gaps; knowledge of an administrative language; social integration); the document list (proof of residence, language certificate, etc., per commune); the filing surface (commune État Civil); the typical timeline; the failure modes. Sources: Code de la nationalité belge art. 12bis (Belgilex link); Moniteur belge official text; the commune's published procedure page where available. - The **three legalisation sub-skills** ship at their current `alpha` status. Promotion to `beta` happens at v1.1+ after each has been exercised through at least one real customer session. - The harness chooses among the three sub-skills deterministically: once the customer's origin-country treaty status is known (one of `hague-acceded`, `non-treaty`, `eu-member-civil-status`), the harness loads the matching sub-skill via the `` composition tag in nationality's body or via the explicit `requires:` edge in the graph. ### 2.5 No-skill-fallback meta-skill (`meta-no-skill-fallback`) Per §24.8 (see architecture.md), the no-skill-fallback meta-skill is the routing floor for procedures Be Civic doesn't yet cover. It ships at v1 so referrals (or the friend if she pivots mid-session to a non-nationality task) get a graceful "Be Civic doesn't have this verified yet, here's what I'll do anyway" response. v1 deliverable shape: - `bc-docs/skills/meta-no-skill-fallback/canonical.md` — new skill canonical. Carries the §24.8 obligations as customer-facing instructions: acknowledge openly, run Be-Civic-style, follow research-method guidance (Belgilex / commune sites / Moniteur belge primary; blog posts and social media advisory only; sources >12 months flagged), identify and reuse corpus sub-skills, offer skill-draft submission at session end. Status `beta` at v1 ship. - **D1 catalogue row** with `applies_to: meta`. The harness's `get_graph` always returns this node when filters don't otherwise match. - **Harness routing logic** in `harness-CLAUDE.md` §3 step 4 on zero-match loads the meta-skill via the standard skill-tool route, identical to loading any procedure skill. What v1 does NOT include from §24.8: the skill-draft submission flow degrades to producing a draft markdown blob and instructing the customer to copy/paste into the manual form at `becivic.be/agents/submit/draft`; the drafting-skills skill review is queued for v1.1. ### 2.6 Profile fields used in v1 `profile.json` schema is the v1 catalogue per `schemas/profile.schema.json`. The v1 harness populates and reads only the fields nationality requires: - `region`, `commune_nis5`, `administration_language`, `conversation_language` (routing) - `nationality_status` (eligibility check) - `residency_status`, `residency_history` (5-year continuity check) - `employment_history` (continuity supporting evidence) - `civic_status`, `dependents` (procedure variations: cohabitant-legal, minor children) - `document_inventory.has_id_card` and other doc-presence booleans (forward dependency on the universal proposal landing `has_id_card`) - `browser_driving_preference` (forward dependency) - `consent` block: `alpha_bundle` / `signed_at` / `version` (forward dependency; alpha-operational per §3.8) - `active_procedures` (starts with `["nationality-application"]` once she commits) Other fields (`education_history`) are part of the schema but not elicited or read in v1. **Date precision — `YYYY-MM` uniformly across all date fields.** Every date field in `profile.json` is encoded as `YYYY-MM`. Day-level precision MAY be held in `/.be-civic/sessions//facts.json` for the active session only (for deadline reminders) and MUST NOT enter persistent state. See privacy.md §8.7.4 "Date precision". ### 2.7 Concerns (HTTP submission MUST work, MCP MAY work) The 2026-05-15 taxonomy normalization renames `observation` → `concern` and replaces the three-value `event_type` enum with `target_type` as the sole discriminator. The harness MUST submit concerns during her session when: - A document name or fee value in the skill turns out to differ from what she encountered → `concern` with `target_type=volatile_value`. - The skill's guidance is unclear, wrong, or missing context for her specific situation → `concern` with `target_type=skill`. - She mentions a procedure or sub-procedure Be Civic does not have a skill for → `concern` with `target_type=skill_graph`. **This MUST happen only after the gate-skill classifier has classified the opener as procedure-intent and after the user has accepted the confirmation gate** — meta-question and exploring shapes never produce a `skill_graph` concern. (Gate-classifier ordering per skills.md §15.7 obligation 12 update — forward dependency on the universal proposal.) Submission path: - MCP configured: `mcp__becivic__submit_concern` is the deterministic path. - MCP absent: HTTPS `POST https://becivic.be/api/concerns` per-type endpoint with the v4 concern schema body, or `POST /api/feedback` polymorphic envelope. All submissions are gated on `profile.consent.alpha_bundle: true` per §3.8. ### 2.8 agents.mdx boot loader on becivic.be The revised boot loader deployed to `becivic.be/agents`. It must include plugin install instructions (the canonical entry point per architecture.md §3 principle 13), the marketplace-by-GitHub-URL path, and the zip-upload fallback per §1.1. Tier-detection prose is retired — under the plugin model, the agent operates inside the plugin runtime with filesystem-availability assumed; degradation to advice-only happens only when the filesystem write probe fails (preamble emits `bundle_root_read_only`). ### 2.9 Filesystem layout under the Cowork host Under the Cowork plugin (V1 onwards), `` resolves to **`/BeCivic/`** — the user picks the parent folder via the Cowork host's directory picker (`mcp__cowork__request_cowork_directory`) at form-submit time per §3.3. The previous flat-`~/.be-civic/` layout is retired under the Cowork plugin path. Profile and shared state live at the BeCivic root; per-procedure state lives in a project subfolder named after the procedure. Multiple projects coexist under the same BeCivic root for the same user. ``` /BeCivic/ ├── CLAUDE.md # ONE harness CLAUDE.md at the BeCivic shared root; services every procedure ├── profile.json # shared across the user's procedures; see privacy.md §8.7.4 ├── MEMORY.md # shared narrative index across procedures ├── trust_contract_seen.json # all-null in V1; scaffolded for future use (D46 dropped) ├── privacy-attachment.md # copy from plugin (D49); alpha-specific terms, user-readable ├── .be-civic/ # hidden directory holding system-only state │ ├── marker # plugin-recognises-folder marker; lives here, not in per-procedure subfolders │ └── sessions/ │ └── / # per-session ephemeral state; deleted on session close │ ├── facts.json │ ├── dossier-draft.md │ └── observations-buffer.jsonl ├── / # one subfolder per procedure (e.g. naturalisation/) │ │ # NO CLAUDE.md here — Cowork auto-load walks ancestors and picks up BeCivic/CLAUDE.md │ ├── procedure_progress.md # narrative + state for this procedure │ ├── documents/ # original documents the user uploaded (lazy — only when there's content) │ └── memory/ │ └── research-notes-*.md # session-scoped research notes; per-procedure narrative ├── / # additional projects coexist; same NO-per-procedure-CLAUDE.md rule ├── submissions.jsonl # cumulative receipt log of all submitted items (shared) └── analytics-outbox.jsonl # offline queue for analytics events (shared) ``` **Note: ONE shared-root CLAUDE.md, no per-procedure copies.** A single `CLAUDE.md` lives at the BeCivic shared root (`/BeCivic/CLAUDE.md`) and services every procedure under it. Cowork's `CLAUDE.md` auto-load convention walks ancestors when the user opens any procedure subfolder, so the BeCivic-root CLAUDE.md is the one that loads regardless of which procedure subfolder the user is in. Per-procedure subfolders MUST NOT carry their own `CLAUDE.md` — Cowork's surface does not support per-subfolder CLAUDE.md branching, and a per-procedure copy would duplicate the harness body and risk drift between procedures. The shared-root model is also consistent with how `profile.json` and `MEMORY.md` are shared across procedures. **Marker location.** The marker lives at `/BeCivic/.be-civic/marker` — inside the hidden `.be-civic/` directory at the **BeCivic shared root**, not in per-procedure subfolders. The hidden subdirectory keeps system state out of the user's sidebar. The `be-civic` gate skill walks cwd ancestors and finds the marker at the BeCivic root regardless of which procedure subfolder the user is currently in. System-only files (marker, future internal state) live in `.be-civic/` at the BeCivic root OR remain in the plugin install itself if they don't need to be in the user's folder. Older Be Civic projects created before the hidden-subdir convention used a top-level `.be-civic-project` marker; the `be-civic` gate skill checks that fallback location and offers to migrate. **Lazy subfolder creation.** The harness does NOT create empty placeholder subfolders at mount time. `documents//` gets created when `bc-document-handler` first writes a document. `.be-civic/sessions//` gets created when the first observation lands or session state needs to persist. The project root stays clean — from the user's sidebar perspective they see only what they can read and understand (CLAUDE.md, profile.json, MEMORY.md initially; documents/, research-notes/ later as they accumulate). System state lives under `.be-civic/` and stays hidden. **`.gitignore` note.** Any harness writing to a `/BeCivic/` directory inside a git-tracked tree MUST add `BeCivic/` (or the absolute equivalent) to the nearest `.gitignore` before writing the first file. **Latin-script paths (G20).** On-disk folder names use Latin-script (ASCII) only — `` is the kebab-case procedure id or a transliterated slug from a user-provided label. The display layer (chat acknowledgements, file-list summaries) MAY render in the user's preferred script. **"Project" terminology kept (D48 dropped).** Context disambiguates Be Civic projects from Cowork's project concept. Plugin documentation MAY use "Be Civic project" where ambiguity is plausible. Other harnesses (the future ChatGPT-app harness, etc.) may have different on-disk semantics — or no on-disk semantics at all. Each harness spec documents its own filesystem-or-not story. ## 3. Onboarding flow (Cowork host) This section specifies the **Cowork host** instantiation of the universal onboarding flow defined in architecture.md §24.6 (per the 2026-05-18 onboarding-rebuild sibling amendment — forward dependency). The universal flow has three beats: gate-classification + confirmation, branded form delivery, and folder-mount-after-submit. This section pins each beat to Cowork primitives (`mcp__visualize__show_widget`, `sendPrompt`, `mcp__cowork__request_cowork_directory`) and lists the on-disk fallback HTML file paths. The flow is owned by the **`bc-onboarding`** skill (first-contact only per D34); the **gate skill (`be-civic`)** classifies before `bc-onboarding` loads. ### 3.1 Gate classification and confirmation gate (Cowork shape) The gate-skill classifier and confirmation gate fire on the Cowork host as **plain chat prose** — no widget, no branded surface. The user sees ordinary chat output from their agent. The confirmation copy adapts to skill-match confidence (high/medium/low per D18). Plugin install opted the user into the conversation; the folder ask opts them into putting files on disk (D1). Cowork doesn't add anything specific here; the universal flow runs as-is. On user "yes" to the confirmation gate, the agent proceeds to §3.2 (form delivery). On "no," graceful exit (*"No problem — I can keep helping with that without Be Civic. Let me know if you change your mind."*). No `mcp__cowork__request_cowork_directory` call, no folder created. ### 3.2 Branded form delivery (Cowork shape) After the confirmation gate is accepted, the agent surfaces the **pre-form loading message** (D19) as a plain chat message: > "Okay, I'm going to pull together an onboarding form for you. Just give me a moment while I analyse your case." The agent then fires one MCP call (single round-trip per D43): - With a candidate procedure: `mcp__becivic__read_skill(skill_id, with_form: true, app: "cowork", locale, mode: "first-contact", pre_selected, profile_snapshot)`. Returns `{canonical, form_html}` — the canonical body for the agent's context, the branded HTML for `mcp__visualize__show_widget`. **Forward dependency** on universal proposal. - Without a candidate procedure (low-confidence intent): `mcp__becivic__get_onboarding_form(app: "cowork", locale, pre_selected)`. Returns `{form_html}` — section-1-only HTML; the agent runs skill-match against the form's answers post-submit. **Forward dependency** on universal proposal. The agent calls **`mcp__visualize__show_widget`** with the returned `form_html`. The user sees the Be Civic-branded onboarding form rendered inside the Cowork chat surface as a widget. **Branded HTML widget specifics (Cowork-only).** - The widget HTML uses the Version-1 styling (D25): cream pills (`#f5f4ee`, weight 500) at rest, gold (`#fae042`, weight 700) when selected. Inputs white with thin hairline border. Submit = ink-body dark CTA. - Bare form elements (`