@twentytwohundred/2200-cli 0.0.0 → 2026.612.1935

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,207 @@
1
+ # Changelog
2
+
3
+ All notable changes to 2200 are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow calendar versioning: `YYYY.M.D` (the UTC date of the cut, no leading zeros, at most one release per day), so an operator can read at a glance how far behind they are. Versions before 2026.6.12 followed semver; `0.1.0` below was never published.
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [2026.612.1935] ... 2026-06-12
10
+
11
+ First release published to the npm registry. Versioning extends to `YYYY.MDD.HHMM` (month+day packed into the minor slot, UTC time of the cut in the patch slot) per the v2 decision ... npm rejects four-segment versions, so `2026.612.1935` is the three-slot form of "June 12 2026, cut at 19:35 UTC". Same-day releases are now possible ... this cut supersedes the same-day `2026.612.1857` attempt, which npm's name filter rejected and which never reached any registry.
12
+
13
+ ### Changed
14
+
15
+ - **Package renamed to `@twentytwohundred/2200-cli`.** npm's registry blocks new all-numeric package names ("That word is not allowed"), confirmed empirically: a minimal stub under `@twentytwohundred/2200` was rejected while `@twentytwohundred/2200-cli` and `@twentytwohundred/cli` both published cleanly. The `2200` binary name, the `curl https://2200.ai/install.sh | sh` one-liner, and all on-disk paths are unchanged ... only the npm package name moved. npm offers no allowlisting path for blocked names (their name-claim process covers trademark disputes only), so `2200-cli` is the permanent package name. `@twentytwohundred/cli` is held as a claimed alias.
16
+
17
+ ### Fixed
18
+
19
+ - **`pnpm verify` builds before testing.** The release workflow's first-ever run exposed a deterministic ordering bug masquerading as the old chaos-test flake: `verify` ran tests before build, but `supervisor-bounce-survival` spawns a real Agent from `dist/runtime/agent/bootstrap.js`, which doesn't exist on a fresh runner. The Agent spawn died instantly and the registration predicate timed out at 20s ... three consecutive release failures. `ci.yml` was already immune via an explicit Build-before-Test step; local `verify` also no longer silently tests a stale `dist/`. (#268)
20
+
21
+ ## [2026.6.12] ... 2026-06-12
22
+
23
+ First published release ... the first 2200 version to reach the npm registry and GitHub Releases, and the first under calendar versioning.
24
+
25
+ ### Fixed
26
+
27
+ - **CLI sources `runtime.env` and `oauth-apps.env` on every invocation** via a commander `preAction` hook, so any command that reads a provider key (`agent build` auto-pick, `oauth login` cred checks, direct `resolveProvider` calls) works from a bare shell instead of failing despite correctly stored keys. Live regression 2026-06-03. (#265)
28
+ - **`Supervisor.stopAgent` kills orphaned Agent processes when the tracked map is empty**, so a stop request can no longer leave an untracked Agent process running. (#263)
29
+
30
+ ### Added
31
+
32
+ - **Paste-a-key provider setup in first-run.** The first-run wizard offers an API-key path alongside the SuperGrok OAuth sign-in, so a new install can bind any supported provider without leaving the terminal. (#264)
33
+
34
+ - **Embassy arc cleanup pass (Phase 2 / PR-B6).** Final piece of the embassy/shelf arc. Completes the `connector.embassy_*` audit family and validates the full chain end-to-end with an integration test.
35
+ - **Three new audit events** (normal tier — operator-noteworthy lifecycle):
36
+ - `connector.embassy_registered` — fires when an embassy / conduit binding is established (atomic or two-step path).
37
+ - `connector.embassy_retired` — fires when a conduit is retired and stops routing.
38
+ - `connector.embassy_shelf_approval_resolved` — fires on operator approve / reject of a pending shelf placement. Decision recorded in extras.
39
+ - **`Supervisor.rejectShelfPlacement`** now reads the pending approval before deleting so it can emit the rejected event with the correct embassy context.
40
+ - **End-to-end chain test** at `tests/runtime/mcp/connector/embassy/chain.test.ts` exercising the locked shape: register embassy → contribute (lands in embassy brain) → embassy autonomous `shelf_place` → embassy `shelf_request_human_placement` → operator approves → `buildShelfPreview` surfaces all items with `self_reflected` + prefix-variation by `source_type` → `applyCollectionTransition` on one-shot transitions to collected → standing item stays pending. Validates both data flow and audit-event flow. Three test cases (full chain, retire fires event, reject fires event).
41
+
42
+ - **Settings UI for embassies + atomic OAuth-and-embassy registration (Phase 2 / PR-B5).** Operator polish on top of the embassy substrate. The "register a connection to Grok" intent now maps to one Settings flow, not two cascading ones.
43
+ - **`Settings → Embassies`** sub-section: list of registered conduits with mode, external model, embassy agent, registered-at, last-seen-at. Two-step retire confirm (no `window.confirm`). Same idiom as `Settings → OAuth Clients` and `Settings → Work Packages`.
44
+ - **Atomic registration form**: one submit mints the OAuth client + provisions the embassy Agent. Result page shows the full paste block for `grok.com/connectors → Custom` (MCP server URL, Client ID, Authorization/Token endpoints, scopes, Token Auth Method). When mint_secret is enabled the client secret is shown once.
45
+ - **Rollback on failure**: if embassy registration fails after the OAuth client is minted, the client is automatically revoked so operators aren't left with orphaned credentials.
46
+ - **Daemon HTTP routes** (loopback): `GET /api/v1/connector/conduits`, `POST /api/v1/connector/conduits` (atomic), `POST /api/v1/connector/conduits/:id/retire`. Mirror the CLI verbs `2200 connector mcp register|list|retire` plus the atomic variant.
47
+ - **`Supervisor.registerEmbassyAndOAuthClient`** is the new atomic primitive — wraps `registerOAuthClient` + `registerEmbassy` with rollback semantics. Existing CLI verbs continue to use the two-step path.
48
+ - **`shelf_pull` MCP tool + `get_fleet_context.shelf_preview` surfacing (Phase 2 / PR-B4).** The moment Grok actually sees the continuity primitive. With this in, the full embassy + shelf + preview + pull + self-reflected + one-shot-collection chain works end-to-end against the real grok.com flow.
49
+ - **`shelf_pull(shelf_item_id)`** new MCP tool. Routes via OAuth `client_id` → conduit → embassy. Returns the full body + provenance summary. For one-shot types (`question`, `research_request`) the type-driven collection transition (PR-B2's `applyCollectionTransition`) fires server-side — same-call-session enforcement of the locked "collected" rule. Standing types stay pending after pull (continuous re-surfacing). Already-collected items return the body without re-firing the transition. Cross-conduit refusal: items attributed to a different OAuth client_id return `unknown shelf_item_id` (threat-model tightening).
50
+ - **`get_fleet_context.shelf_preview`** optional response block. Hard cap 10 inline items + `next_priority_ids` long-tail (next 10 IDs without content). Priority order per spec section 7 verbatim: standing-pending first, then high-priority, then most-recent `ingested_at`, with collected-standing items below pending. Deterministic score formula for reproducible test ordering. Block omitted entirely when the caller has no registered conduit (static-bearer / unregistered OAuth).
51
+ - **`self_reflected`** detection: true when an item's `source.client_id` matches the calling OAuth client. Excerpt is prefixed by a model-readable sentence varying by `source_type`: "the fleet flagged it for your return" (embassy_autonomous) vs "an operator curated it for your return" (human_curated). Stateless-client compatible — no session bookkeeping needed.
52
+ - **Excerpt** is the first 500 chars of the item body, truncated on a word boundary with `...` appended.
53
+ - **Two new audit events**: `connector.embassy_shelf_pulled` (passive; fires on every `shelf_pull`) and `connector.embassy_shelf_preview_surfaced` (passive; once per `get_fleet_context` call with a non-empty preview, counts `items_surfaced` + `self_reflected_count` + `total_pending`). Rest of the `connector.embassy_*` family lands in B6.
54
+ - **`propose_work_package` + `get_research_brief` route through the embassy (Phase 2 / PR-B3b).** Fast follow-up to PR-B3 part 1. The remaining two connector tools now respect embassy routing; reads search across the shared brain + every registered embassy so operator workflows (CLI approve, web Settings tile) work without the operator naming a specific embassy.
55
+ - **`writeProposedPackage`** gains an optional `embassyAgent` parameter. When set, the package note lands in the embassy's brain (tagged `relationship-history` + `work-package`) instead of the shared brain.
56
+ - **`Supervisor.proposeWorkPackage`** threads `callingClientId` through and calls `resolveCallingEmbassy` to pick the embassy. The MCP tool plumbs `callingClientId` from `ConnectorMcpServerDeps`.
57
+ - **`readWorkPackage` / `listWorkPackages` / `patchPackageFrontmatter`** search across the shared brain + every registered embassy brain; reads and lookups don't require operator-supplied embassy context. List aggregates with dedup by `package_id`.
58
+ - **`readBrief`** (the read side of `get_research_brief`) searches shared brain first, then every registered embassy. Briefs synthesised after B3 land in the embassy that owns the conduit.
59
+ - **`locatePackageStore`** helper centralizes the cross-store search pattern; same shape adopted in `readBrief` for briefs.
60
+ - **`contribute_to_thread` routes through the embassy + one-time pre-embassy note migration (Phase 2 / PR-B3 part 1).** Connector contributions now land in the embassy's brain (tagged `relationship-history`) for OAuth-authenticated callers with a registered conduit. When the first conduit is registered, existing pre-embassy notes are migrated to the new embassy automatically (sentinel-tracked, idempotent).
61
+ - **Routing helper** `resolveCallingEmbassy(home, callingClientId)` — single lookup surface from OAuth `client_id` → conduit → embassy. Returns null for static-bearer callers and unregistered clients; tools fall back to legacy ownerless-note behavior. Records `last_seen_at` on the conduit on every match.
62
+ - **`contribute_to_thread` migrated**: both thread and agent targets route through the embassy when one is registered for the calling OAuth client. Thread anchors land in the embassy's brain (tagged `research-thread` + `relationship-history`); per-Agent contributions land in the embassy's brain too with `target_agent` preserved in extras for cross-reference.
63
+ - **`callingClientId` plumbed end-to-end**: the listener's `/mcp` preHandler stashes the verified OAuth client_id on the request; the per-request MCP server receives it via `ConnectorMcpServerDeps`; tool handlers look up the embassy through the routing helper.
64
+ - **One-time migration** at first-conduit-register time. Migrates research threads + standing briefs from `<shared>/brain/` + per-Agent grok-contributions from every Agent's brain into the embassy's brain. Sentinel at `<home>/state/connector/note-migration-complete.json` guards re-runs; idempotent. Per-Agent contributions retain `target_agent` extras. Operator can force a re-run via `clearMigrationSentinel` (post-retire-and-re-register recovery).
65
+ - **`propose_work_package` and `get_research_brief` migrations** ship in a parallel small PR (B3b) to keep PR-B3 reviewable.
66
+ - **Embassy shelf data model + nine internal tools + sensitivity gate (Phase 2 / PR-B2).** Second slice of the embassy/shelf arc. Lays the shelf substrate; the connector tools migrate through it in B3; remote-model surfacing in `get_fleet_context` lands in B4.
67
+ - **Shelf data model** per spec section 5 verbatim. Items live at `agents/<embassy>/brain/shelf/<shelf-item-id>.md`, frontmatter-typed (Zod-validated) with full provenance (`source.client_id` for `self_reflected` detection, `provenance.ingested_at` / `_by` / `chain`). `shelf_item_id` is `shelf_<24 base32>`. Item types are `question`, `context`, `research_request`, `synthesis_prompt`, `agenda`; one-shot vs standing collection semantics per spec section 6.
68
+ - **Nine internal tools** (spec section 8 + the `shelf_read` Grok approved in the final pass), all under the `shelf_` namespace per the runtime's `<namespace>_<verb>` convention. Spec → runtime mapping documented inline:
69
+ - `shelf_place` (spec: `place_on_shelf`) — writes a `pending` item.
70
+ - `shelf_resolve` (spec: `resolve_shelf_item`) — forces `collected`.
71
+ - `shelf_reopen` (spec: `reopen_shelf_item`) — `collected` → `pending`.
72
+ - `shelf_reprioritize` (spec: `reprioritize_shelf_item`).
73
+ - `shelf_remove` (spec: `remove_from_shelf`) — deletes the file.
74
+ - `shelf_list_mine` (spec: `list_my_shelf`) — full bodies; embassy-internal, distinct from the bounded preview that lands in B4.
75
+ - `shelf_read` (new) — single-item full body + frontmatter; embassy-internal pull path.
76
+ - `shelf_curate_from_inbox` (spec: `curate_from_inbox`) — moves operator-curated items to the shelf with `source_type: human_curated`.
77
+ - `shelf_request_human_placement` (spec: `request_human_shelf_placement`) — only path for items needing operator approval.
78
+ - **Sensitivity gate (locked 2026-05-26)**. `shelf_place` rejects `sensitivity: 'private'` at the Zod schema layer (the enum is restricted to `'none'`); `shelf_request_human_placement` is the only path. Operator approval via `2200 connector mcp shelf approve <token>` writes the item with `source_type: human_curated` and the operator's name as curator — the human approval IS the desensitization.
79
+ - **Rate limiting (locked 2026-05-26)**. In-memory rolling 60-second window per embassy. System defaults 20/min soft (audit-only) + 100/min hard (rejects with `ToolDeniedError` reason `placement_rate_exceeded`). Per-embassy overrides on the conduit record's optional `rate_limits` block. Resets on Agent restart.
80
+ - **Five audit event types**: `connector.embassy_shelf_item_placed` (passive, fires on every successful write including post-approval), `_item_resolved` (passive, manual + auto), `_human_approval_requested` (normal, the operator-actionable event), `_item_read` (passive, embassy reads its own shelf), `_rate_threshold` / `_rate_exceeded` (normal / important, burst guard).
81
+ - **CLI verbs**: `2200 connector mcp shelf approve <token> [--operator-name <name>]` and `2200 connector mcp shelf reject <token>` for the human-approval flow.
82
+ - **Dedicated-embassy registration** now defaults `tools:` to include all nine shelf tools so the embassy can actually use the shelf out of the box; attached mode preserves existing tools (operators add explicitly).
83
+ - **Spec→runtime "collected" rule** (per Grok's 2026-05-26 wording): an item is considered collected only when the remote model has received the full (or sufficient) body during the same inbound call session, not when it has only seen a preview. The `applyCollectionTransition` helper enforces type-driven rules: one-shot types → `collected`, standing types stay `pending` after the model pulls.
84
+ - **Embassy substrate + conduits registry (Phase 2 / PR-B1).** First slice of the locked embassy/shelf arc (spec: `wiki/inbox/grok/2026-05-23-embassy-shelf-handoff.md`). Lays the substrate; subsequent PRs in the arc layer on top.
85
+ - **`embassy` block on the identity frontmatter** marks an Agent as currently acting as a fleet embassy for an external MCP-speaking model. Records `external_model`, `client_id` (the OAuth client this embassy serves), `mode` (`dedicated` or `attached`), `registered_at`. Optional + additive; existing identity files parse cleanly.
86
+ - **Conduits registry** at `<home>/state/connector/conduits/<client_id>.json`, keyed by OAuth `client_id` per the 2026-05-26 locked decision. The access token at `/mcp` already carries `client_id`, so subsequent PRs route to the right embassy without an extra lookup. Operator-visible projection regenerates at `<shared>/brain/conduits.md` (same pattern as `<home>/state/fleet.md` — rebuildable mirror, never edit by hand).
87
+ - **`Supervisor.registerEmbassy({client_id, external_model, embassy_agent, mode, display_name, ...})`** — validates the OAuth client exists + isn't revoked, ensures no existing conduit for the same client, then either creates a fresh Agent with the embassy identity template (dedicated) or patches an existing Agent's identity with the embassy block (attached). Initializes the embassy's brain subdirs per spec section 4: `shelf/`, `relationship-history/`, `standing-briefs/`, `notes/`. Writes the conduit record + regenerates the shared-brain index.
88
+ - **CLI** under `2200 connector mcp <verb>` per spec section 10:
89
+ - `register --client-id <id> --external-model <name> --embassy-agent <name> --mode dedicated|attached --display-name <text>` (with `--model-tier`, `--model-provider`, `--model-id` for dedicated mode)
90
+ - `list` — table of registered conduits with mode, last-seen, retired-at
91
+ - `retire <client-id>` — marks the conduit retired; the OAuth client + embassy Agent stay intact
92
+ - **Embassy identity template** (spec section 3, verbatim shape): the Agent's role is the "<External> Embassy," explicit memory rules forbid pushing information outward, the conduit-status block carries connection metadata. Persona text loads as a normal system prompt.
93
+ - **OAuth Settings UI + runbook + grok.com defaults (Phase 2 / PR-A2).** Operator-facing polish on top of the PR-A1 substrate.
94
+ - **`Settings → OAuth clients`**: Web Settings page gains a sub-section for registering / listing / revoking / rotating OAuth clients. Same two-step destructive confirms and copy-on-show secret-display discipline as `Settings → Work packages`. Register form defaults the redirect URI to the canonical grok.com callback discovered empirically 2026-05-23 (`https://grok.com/connectors-oauth-exchange-code/`); the result page prints the full block of values to paste at `grok.com/connectors → New Connector → Custom`.
95
+ - **CLI default**: `2200 connector oauth-client register` now defaults `--redirect-uri` to the canonical grok.com callback. Override with the flag for other consumer-side MCP clients (Claude Desktop, ChatGPT MCP, etc.).
96
+ - **`GROK_CONNECTOR_REDIRECT_URI` exported** from `src/runtime/mcp/connector/oauth/client-store.ts` so the CLI, daemon, and runbook stay in sync on the canonical value.
97
+ - **`/.well-known/oauth-protected-resource`** (RFC 9728): protected-resource metadata published. grok-connectors-manager/0.1.0 probes this on every connect; cheap spec compliance.
98
+ - **Daemon HTTP routes** (loopback): `GET /api/v1/connector/oauth-clients`, `POST /api/v1/connector/oauth-clients`, `POST /api/v1/connector/oauth-clients/:id/revoke`, `POST /api/v1/connector/oauth-clients/:id/rotate-secret`, `GET /api/v1/connector/grok-redirect-uri`. Same Supervisor methods the CLI verbs already hit.
99
+ - **Operator runbook** at `wiki/grok-connector-setup.md` rewritten to reflect the empirical reality: choose-your-auth-path table, OAuth registration walkthrough, the static-bearer path documented separately. The Tesla / in-car section preserves "verify on your hardware" verbatim and explicitly notes it does not change until Doug personally watches it fire.
100
+ - **MCP connector OAuth 2.0 Authorization Server (Phase 2 / PR-A1).** Resolves the architectural gap discovered when Doug hit grok.com/connectors → New Connector → Custom: the consumer UI requires OAuth 2.0 + PKCE, not the static bearer Phase 1 shipped. The connector now serves both: the static bearer continues to work for developer-API callers (Claude Desktop, headless scripts), and a full OAuth AS now serves consumer-grade Grok / Tesla.
101
+ - **OAuth endpoints** on the existing `:2201` connector listener: `GET /oauth/authorize` (code grant with mandatory PKCE S256), `POST /oauth/token` (code exchange + refresh-token rotation), `POST /oauth/revoke`, `GET /.well-known/oauth-authorization-server` (RFC 8414 metadata).
102
+ - **Pre-authorize-at-registration consent model** (locked with Grok 2026-05-23): the operator registers each client at the trusted loopback surface via `2200 connector oauth-client register --display-name <...> --redirect-uri <...>`. Subsequent `/authorize` requests over the public tunnel proceed without operator presence, validated against the registered set. Zero operator-facing UI is exposed through the tunnel — preserving Phase 1's loopback-only operator-surface invariant absolutely. The pre-authorization step IS the human security boundary.
103
+ - **Opaque tokens, sealed vault** (parallel to PR 1a's `bearer-store`): `2200-mcp-at-<43 base64url>` access tokens (24 h TTL default), `2200-mcp-rt-<43 base64url>` refresh tokens (90 d TTL default, with rotation_chain replay-detection per RFC 6749 BCP), in-memory authorization codes (60 s, one-time-use). Distinct HKDF namespaces; on-disk filenames are SHA-256 prefixes of the token (`ls` does not expose secrets).
104
+ - **Refresh-token reuse detection.** Each refresh has a `chain_id` + `rotated` flag. Successful refresh marks the consumed token rotated. Reuse of a rotated token triggers `revokeChain(chain_id)` and emits `connector.oauth_refresh_reuse` (important tier) — the canonical compromise signal.
105
+ - **Bearer ↔ OAuth coexistence on `/mcp`.** Token-prefix disambiguation: the listener's preHandler tries OAuth access-token verification first (when `Bearer 2200-mcp-at-...`), then falls through to the static-bearer constant-time-compare (Phase 1). Both auth paths live on the same endpoint; Phase 4's dispatcher hard-guard remains the real permission boundary regardless of which path authorized the request.
106
+ - **Strict redirect-URI pre-registration** (no TOFU, no pattern matching). The operator pastes Grok's exact callback URL at registration time. `/authorize` rejects any unregistered redirect with `invalid_request` + a 400 response (no open-redirector hazard).
107
+ - **PKCE S256 mandatory; `plain` rejected.** Client secrets are optional (PKCE-only is the recommended path matching grok.com's "Token Auth Method: none" default). When the operator opts in to a secret with `--mint-secret`, it's scrypt-derived-and-stored; the plaintext is shown once at registration time and never re-exposed (parallel to the static-bearer regenerate UX).
108
+ - **CLI** (`2200 connector oauth-client register | list | rotate-secret | revoke`). The `register` output prints the exact block the operator pastes into grok.com/connectors → Custom (MCP server URL, Client ID, Authorization Endpoint, Token Endpoint, Scopes, Token Auth Method).
109
+ - **Audit event family** `connector.oauth_*`: `client_registered` / `client_revoked` (lifecycle), `authorize_succeeded` / `authorize_rejected` (per-request), `token_issued` (initial grant + refresh rotation), `refresh_reuse` (important tier, fires on compromise).
110
+ - **Work-package approval Settings tile + operator runbook (PR 5).** Phase 1 wrap-up.
111
+ - **Settings page tile** (`Settings → Work packages`) renders proposals handed in via `propose_work_package`. Filter by "Awaiting review" (default) or "All packages." Each package card shows summary + plan + risks + success criteria parsed from the body, with one-click Approve (two-step confirm) or Reject (optional reason). Approval routes the plan to the primary Agent via the existing task-submit substrate; rejection records the decision. Auto-refreshes every 15 s.
112
+ - **Daemon HTTP routes** (loopback): `GET /api/v1/connector/work-packages` (with optional `?status=<...>` filter), `POST /api/v1/connector/work-packages/:id/approve`, `POST /api/v1/connector/work-packages/:id/reject` (`{ reason? }`).
113
+ - **`listWorkPackages` library helper** in `runtime/mcp/connector/work-package.ts`. Sorted by createdAt descending, filtered by status, body included so the UI renders the parsed sections without a second round-trip.
114
+ - **Post-regenerate copy-toast polish** on the MCP connector tile: after the operator clicks Copy on the freshly-minted token, the tile shows a short success-state pointing at the `grok.com/connectors` paste destination. Closes a minor PR 1b review note from Grok.
115
+ - **Operator runbook** at `wiki/grok-connector-setup.md`: tunnel options (ngrok quick-start, Cloudflare Tunnel, Tailscale Funnel), the grok.com/connectors registration walkthrough, in-car verify-on-your-hardware language verbatim from the locked Phase 1 handoff, security-posture summary, common knobs, troubleshooting.
116
+ - **MCP connector `propose_work_package` + dispatcher hard guard (PR 4).** Grok (or any other MCP connector caller) can hand a proposal of real work to the fleet — the safety-load-bearing piece of the connector substrate.
117
+ - **New MCP tool** `propose_work_package`. Returns `{ status: 'queued_for_review', package_id, package_slug, coordination_task_id }`. The proposal lands as a normal Brain note at `<shared>/brain/work-package-<id>.md` (tagged `work-package`); the primary Agent gets a strict-allowlist coordination task that produces a reviewable plan.
118
+ - **Hard guard in `ToolDispatcher`** (mechanical, not advisory). Two new task-frontmatter fields: `tool_policy: inherit_agent | strict_allowlist` (default `inherit_agent`, existing tasks unaffected) and `allowed_tools: string[]`. The dispatcher rejects off-list calls with `ToolDeniedError(name, 'task_allowlist_violation', ...)` BEFORE the existing identity-level check. Per-task cached lookup.
119
+ - **Two restricted task kinds in Phase 1**: `work_package_coordination` (allowlist: `brain_read_shared`, `brain_search_shared`, `brain_list_shared`, `brain_write_shared`, `pub_post`, `pub_read`) and `standing_brief_synthesis` (PR 3 retrofit; allowlist: `brain_read_shared`, `brain_search_shared`, `brain_list_shared`, `brain_write_research_brief`). Inline "additions require explicit review" comments per the Grok lock 2026-05-23.
120
+ - **Approval surface (CLI)**: `2200 connector work-package approve <package-id>` / `reject <package-id> --reason <...>`. Approval parses `## Plan` steps and submits normal Agent tasks via `cli.task.submit`.
121
+ - **Five new Inbox events**: `connector.work_package_arrived` / `_plan_ready` (important), `_coordination_failed` / `_approved` / `_rejected` (normal).
122
+ - **Supervisor outcome watcher**: lightweight 30 s poll observes terminal transitions of tracked coordination tasks.
123
+ - **Standing-brief synthesis layer for MCP connector research threads (PR 3).** Long Grok conversations now get high-quality re-engagement: each research thread maintained by a primary Agent who keeps a synthesized standing brief current as new contributions arrive.
124
+ - **Sibling brief note** at `<shared>/brain/research-<slug>-brief.md` (separate from the chronological log shipped in PR 2). Full-rewrite each synthesis; tagged `standing-brief` + `research-thread`.
125
+ - **Provenance** baked into brief frontmatter ... `synthesized_through`, `contribution_count`, `contribution_first_at` / `_last_at`, `contributor_sources`, `synthesizing_agent` ... computed by the write tool from the thread's chronological log, so machine-readable provenance is always present regardless of how the synthesized text cites its sources.
126
+ - **Supervisor-side reconciler** (default 30 s poll, 60 s debounce) detects threads with `pending_synthesis_at > synthesized_through` + debounce elapsed + primary Agent running, and submits a synthesis task via the existing `cli.task.submit` substrate. The Agent's normal loop runs the LLM synthesis; cost stays on the Agent's budget where it belongs.
127
+ - **New baseline tool** `brain_write_research_brief(thread_slug, brief_body, token_usage?, duration_ms?)` is the write surface the synthesizing Agent calls. Resets the thread's failure counter on success.
128
+ - **New MCP tool** `get_research_brief(thread_slug)` exposes the full brief + provenance to the connector caller (Grok). `get_fleet_context` gains a per-thread `brief_excerpt` (first ~500 chars) + `brief_synthesized_through` + `brief_stale` + `brief_blocked` fields so the orientation packet stays small while signaling staleness.
129
+ - **Failure handling**: three consecutive synthesis failures escalate to `synthesis_blocked: true` (tier-`important` Inbox event). Operator clears with `2200 connector synthesis unblock <thread-slug>`.
130
+ - **Inbox events** (all under the `__connector` synthetic emitter): `connector.synthesis_started` (passive), `connector.synthesis_completed` (passive, includes duration + contribution count), `connector.synthesis_failed` (normal / important on block), `connector.synthesis_primary_missing` (normal).
131
+ - **Global synthesis budget guard** (stretch from the locked design): optional fleet-wide cap on connector synthesis spend over a rolling window, off by default.
132
+ - **MCP connector real Phase 1 tools (PR 2).** Two structured tools land on top of the substrate plus the existing `liveness` probe:
133
+ - `contribute_to_thread`: Grok (or any MCP client) hands a structured contribution (`research_findings`, `reasoning`, `sources`, `open_questions`, `proposed_direction`, optional `related_threads`) into one of two destinations via a discriminated `target` union. `{ thread: <name> }` appends a `## <ISO ts>` section to a shared-brain research thread anchor at `<shared>/brain/research-<slug>.md` (created on first contribution, tagged `research-thread`). `{ agent: <name> }` writes the contribution as a standalone Brain note at `<agent>/brain/grok-contribution-<compact-ts>-<hash>.md` (tagged `grok-contribution`). Both paths are normal Brain notes that participate in the existing `brain_search` / `brain_read` surface ... no special-casing in the brain layer. Phase 1 contributions are inert from an execution standpoint (read material only).
134
+ - `get_fleet_context`: small, structured orientation packet (`agents`, `threads`, `recent_activity`) so a returning Grok conversation can pick up cleanly after a long gap. Deliberately small ... PR 3's standing-brief layer is what makes re-engagement high-quality.
135
+ - **`connector.contribution_received` Inbox event** (passive) carrying `target_kind` (`thread` | `agent`), `target_name`, `contribution_slug`, `contribution_path` so the Inbox row links straight to the produced note.
136
+ - **`bodyLimitBytes` operator escape hatch** for the connector listener. Default raised from 1 MiB to 8 MiB (sized for `contribute_to_thread` research blobs); overridable via `TWENTYTWOHUNDRED_CONNECTOR_BODY_LIMIT_BYTES` env var. Trade-off documented in the as-shipped decision record: larger body = larger public-facing DoS surface.
137
+
138
+ ### Changed
139
+
140
+ - **MCP connector Phase 1 substrate polish (PR 1d).** Tidy-up pass after Grok's full byte-level review. Documentation strengthened (X-Forwarded-For tunnel-trust assumption inline in `clientIp`; bodyLimit comment flagging the PR 2 need to widen when `contribute_to_thread` lands with large research payloads; per-fleet-salt WHY in `bearer-store.ts`; first-run wording aligned with the Grok-First step). Sync `getConnectorStatus` renamed to `getConnectorStatusFast` with a strong "not for operator surfaces" guard comment ... the async `getConnectorStatusDetailed` remains the only surface used by CLI / web / RPC. `2200 connector token show` now writes paste guidance to stderr (stdout stays clean for `... | pbcopy`). First-run success message uses the same "sealed to disk" voice as the Grok sign-in step. New regression test for the idle → regenerate listener transition. Decision record at [[2026-05-23-mcp-connector-phase1-as-shipped]] pins the substrate-level decisions before Phase 2 begins.
141
+
142
+ ### Added
143
+
144
+ - **First-run wizard offers MCP connector setup (PR 1c).** After Grok sign-in in the bare-`2200` wizard, the operator is offered a one-question opt-in to mint a connector token inline. Default NO ... keeps the install path uncluttered for users who do not know what MCP is. On yes, the wizard mints the bearer through the daemon's `cli.connector.regenerate` RPC and surfaces the token once with paste-target instructions (`grok.com/connectors` → New Connector → Custom). Failure is non-fatal; the operator can retry via `2200 connector token regenerate` or the Settings tile.
145
+ - **MCP connector Settings tile + daemon routes (PR 1b).** Operator UI for the MCP connector lives in Settings: status line + masked token + reveal + copy + 2-step regenerate / disable. New daemon routes on the loopback web UI listener (`GET /api/v1/connector/status`, `GET /api/v1/connector/token`, `POST /api/v1/connector/regenerate`, `POST /api/v1/connector/disable`). After regenerate the freshly minted token is shown once in a copy-to-clipboard banner with the paste target (`grok.com/connectors` Authorization). Inline two-step destructive confirms (no `window.confirm`).
146
+ - **Web-UI loopback safety check.** At supervisor start, if `TWENTYTWOHUNDRED_WEB_HOST` is overridden to a non-loopback host the daemon emits a `normal`-tier Inbox event (`connector.web_host_non_loopback`) explaining the foot-gun and how to revert. The MCP-connector security model assumes the web UI is loopback-only.
147
+ - **MCP connector substrate (Phase 1 / PR 1a).** 2200 now exposes itself as a remote MCP server, on a dedicated Fastify listener (default `:2201`, configurable via `TWENTYTWOHUNDRED_CONNECTOR_PORT`) isolated from the web UI listener. Bearer-token auth via the sealed vault (constant-time compare, no fallback-allow, 32-byte `2200-mcp-<base64url>` tokens). Every inbound call surfaces as an Inbox event; failed-auth events are throttled per source IP to one per 10 minutes. PR 1a ships the substrate plus a single `liveness` probe tool; the real Phase 1 tool surface (`contribute_to_thread`, `propose_work_package`, `get_fleet_context`) lands in subsequent PRs after Grok's code review on this layer.
148
+ - New `2200 connector` CLI: `token show | regenerate | disable`, plus `status`. `regenerate` and `disable` route through the daemon over UDS so the live listener's cached bearer is swapped atomically.
149
+ - Sealed bearer store at `<home>/state/connector/bearer.json` (AES-256-GCM + HKDF, distinct namespace from the OAuth token store).
150
+ - Inbox audit events: `connector.call_received`, `connector.auth_rejected`, `connector.listener_state_changed`.
151
+ - Architecture review by Grok on listener boundary + auth model before PR; design note at `wiki/inbox/grok/2026-05-22-mcp-listener-auth-design.md`.
152
+ - **Grok-First: SuperGrok / X Premium+ subscription auth (no API key).** Sign in to your existing xAI Grok subscription and every Agent set to the new `xai-subscription` provider uses the subscription bearer ... no `XAI_API_KEY` needed. The API-key path remains as a separate, parallel provider (`xai`).
153
+ - Settings page: prominent "Sign in with X / SuperGrok" tile at the top, with the official Grok logo. Inline device-code flow with a phone-friendly URL + code; auto-polling status until completion. (`#237`)
154
+ - Model picker: new "Subscriptions" optgroup pinned at the top of the dropdown. `xAI / Grok (SuperGrok subscription)` is a selectable provider distinct from the API-key sibling, so the credential choice is visible in the Agent's Identity. (`#238`, `#239`)
155
+ - Auto-restart on model switch: changing an Agent's model from the picker now stops + restarts the Agent so the new credential / provider binding is what serves the next request. Inline spinner during the swap; clear error surface if restart fails. (`#240`)
156
+ - First-run installer: the bare-`2200` wizard now offers Grok subscription sign-in inline (default yes) after user-identity mint, so a new install can leave setup with a working Grok credential without ever pasting an API key. (`#237`)
157
+ - CLI: `2200 oauth xai login | status | logout` for headless / scripted setup. Device-code flow with PKCE S256, public-client OAuth. (`#236`)
158
+ - **Generic device-code OAuth substrate** (`src/runtime/oauth/device-flow.ts`). RFC 8628 with PKCE S256; reusable for any future public-client provider. Handles `authorization_pending`, RFC-spec `slow_down`, `expired_token`, `access_denied`. (`#236`)
159
+ - **Fleet-scoped sealed OAuth token store** at `<home>/state/oauth-tokens/`. AES-256-GCM + HKDF over the per-instance master key with a fleet-scoped HKDF info string. Separate namespace from the per-Agent credential vault. (`#236`)
160
+ - **Background OAuth refresh service.** `TokenRefreshService.tick()` now also scans the fleet OAuth store and refreshes within 120s of expiry using `grant_type=refresh_token`. Same failure-cooldown logic as the existing per-Agent path. (`#236`)
161
+ - **Daemon HTTP endpoints**: `POST /api/v1/oauth/xai/login/start`, `GET /api/v1/oauth/xai/login/status?session=<id>`, `GET /api/v1/oauth/xai/status`, `POST /api/v1/oauth/xai/logout`. Browser-driven device-code flow without leaking PKCE state across requests. (`#237`)
162
+ - **`install.sh` auto-configures `~/.npm-global` on non-writable npm prefix.** Detects the typical Ubuntu/Debian footgun (system `npm` at `/usr` requires sudo), explains the situation in plain language, and auto-fixes it without admin access. Shell-aware (bash / zsh / fish). Idempotent on re-runs. (`#233`)
163
+
164
+ ### Changed
165
+
166
+ - **Chaos test stability**: eliminated the `supervisor-bounce-survival` flake by waiting for the heartbeat loop to cycle before bouncing the supervisor in-test. Root-cause fix, not a retry config. (`#234`)
167
+ - **Adopted `@eslint/js` v10**: bumped from 9.39.4 and adopted the two new rules `preserve-caught-error` and `no-useless-assignment`. 26 violations fixed across the codebase ... most now add `{ cause: err }` chains to thrown errors inside `catch` blocks, so debug sessions see both the symptom and the underlying error. (`#235`)
168
+ - **Lock-based PID liveness** for the supervisor and every Agent. Replaced the historical `kill(pid, 0)` liveness check with `proper-lockfile` lock holdership. Eliminates the stranger-PID hazard (recycled OS PIDs falsely reporting our processes as alive). Migration is operator-walkable: a daemon from a pre-lock release is detected and reported with a clear recovery message. (`#230`)
169
+
170
+ ## [0.1.0] ... 2026-05-20
171
+
172
+ ### Added
173
+
174
+ - **First installable release.** Package published as `@twentytwohundred/2200` on the npm registry.
175
+ - **Shell installer** at `install.sh`. One-liner for any macOS or Linux box with Node 22+: `curl -fsSL https://2200.ai/install.sh | sh`. The 2200.ai URL is an nginx reverse-proxy to the script in this repo, so the install script remains a single source of truth in the repo. Detects Node version, refuses to silently elevate via sudo, and installs the latest published version via the user's `npm`.
176
+ - **Bare `2200` first-run.** When the CLI is invoked with no subcommand and no prior install state, it walks the user through a guided setup: choose `2200_HOME`, initialize the directory layout, start the supervisor daemon, mint the user identity, point at `2200 agent build` for the first Agent. All input is collected before any side effect, so a `ctrl-C` at any prompt is safe.
177
+ - **`2200 update`.** Top-level self-upgrade. Checks the npm registry for the latest published version, prompts (or `--yes`), stops the daemon, installs the new package globally, restarts the daemon. `--check` reports availability without installing. Refuses to auto-upgrade a source checkout.
178
+ - **`2200 --version`** now reads from `package.json` at runtime, so `npm version <bump>` is the single source of truth for the installed CLI version.
179
+ - **Web upgrade button.** Settings → System tile shows current vs. latest version. Click → 2-step inline confirm → the daemon writes `<home>/state/upgrade-status.json`, spawns a detached helper, and shuts itself down. The helper waits for the daemon to exit, runs `npm install -g`, and starts the new daemon. The web UI polls the status throughout, absorbing the brief mid-upgrade outage, and surfaces the per-stage progress.
180
+ - **System HTTP endpoints**: `GET /api/v1/system/version`, `POST /api/v1/system/update`, `GET /api/v1/system/upgrade-status`.
181
+
182
+ ### Notes
183
+
184
+ - 2200_HOME state (under `~/.local/share/2200/` by default, or whatever you chose at first-run) is never touched by `2200 update`. Upgrades only replace the global package binary.
185
+ - Native dependencies (`better-sqlite3`, `sharp`) ship prebuilds for macOS arm64/x86_64 and Linux arm64/x86_64. Other platforms fall through to a build-from-source path that requires a C++ toolchain.
186
+ - Windows is not supported on this release. Use WSL2.
187
+
188
+ ### Added (prior to 0.1.0)
189
+
190
+ - Repository scaffolding: LICENSE, README, AGENTS.md, SECURITY.md, CONTRIBUTING.md, CHANGELOG.md, THIRD_PARTY_NOTICES.md, `.github/` templates and CI workflow.
191
+ - Public wiki at [`twentytwohundred/wiki`](https://github.com/twentytwohundred/wiki), mirrored from the canonical Brain-format tree.
192
+ - Spec scaffolding (in the wiki): vision, architecture, epic map, seed team, 48 decision records, 11 conventions, per-epic specs, design system + design docs, prior-art analysis with deep findings appendix.
193
+ - **Epic 2: Agent runtime minimum.** Shipped. Supervisor, Identity loader, Brain (filesystem-first per [decision record](https://github.com/twentytwohundred/wiki/blob/main/decisions/2026-04-24-brain-is-files-not-database.md)), baseline tool set, plan/run/perm wrapping on every tool call, integer schema versioning everywhere, control-plane protocol over UDS+JSON-RPC.
194
+ - **Epic 3: Local pub integration via OpenPub.** Shipped. Pub supervision substrate, user and Agent pub identities, four pub MCP tools, WebSocket wake source, end-to-end smoke test against `@openpub-ai/pub-server@0.3.3`.
195
+ - **Epic 3.5: Two-agent demo.** Shipped. Hobby↔Simon coordination on the seed-team box, with the published runbook reproducible end-to-end.
196
+ - **Epic 3.6: Multi-provider and ambient routing.** Shipped. Six LLM providers wired (Anthropic native; OpenAI, DeepSeek, Kimi, OpenRouter, Gemini via the OpenAI-compatible adapter and `OPENAI_COMPATIBLE_VENDORS` table). Pub message router service with per-pub roster sidecars, opt-in via `ROUTER_PROVIDER` and `ROUTER_MODEL_ID`.
197
+ - **Epic 3.7: Followup model and chat polish.** Shipped. `Identity.model.followup_model_id` for two-tier model selection per Agent. Chat status notices.
198
+ - **Epic 3.8: Multi-Agent ack-spiral fix.** Shipped. Structural guards in the wake source: skip the router when sender is a known Agent; respect explicit `@`-mentions; per-pub roster self-upsert on Agent start; complete-roster perspective in router input.
199
+ - Local `pnpm patch` for `@openpub-ai/pub-server@0.3.3` (keepalive listener and bartender-guard fixes), to be dropped when v0.3.4 ships upstream. See [openpub-ai/openpub#1](https://github.com/openpub-ai/openpub/issues/1).
200
+
201
+ ### Notes
202
+
203
+ - No tagged releases yet. Versioning begins when the runtime is feature-complete enough for the first public preview.
204
+ - The `wiki/` feature on this repo is disabled; the project knowledge base lives at [twentytwohundred/wiki](https://github.com/twentytwohundred/wiki) (public, markdown on `main`).
205
+
206
+ [Unreleased]: https://github.com/twentytwohundred/2200/compare/v0.1.0...HEAD
207
+ [0.1.0]: https://github.com/twentytwohundred/2200/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,95 @@
1
+ Copyright (c) 2026 TWENTYTWOHUNDRED LLC
2
+
3
+ Elastic License 2.0
4
+
5
+ URL: https://www.elastic.co/licensing/elastic-license
6
+
7
+ ## Acceptance
8
+
9
+ By using the software, you agree to all of the terms and conditions below.
10
+
11
+ ## Copyright License
12
+
13
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
14
+ non-sublicensable, non-transferable license to use, copy, distribute, make
15
+ available, and prepare derivative works of the software, in each case subject
16
+ to the limitations and conditions below.
17
+
18
+ ## Limitations
19
+
20
+ You may not provide the software to third parties as a hosted or managed
21
+ service, where the service provides users with access to any substantial set of
22
+ the features or functionality of the software.
23
+
24
+ You may not move, change, disable, or circumvent the license key functionality
25
+ in the software, and you may not remove or obscure any functionality in the
26
+ software that is protected by the license key.
27
+
28
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
29
+ of the licensor in the software. Any use of the licensor's trademarks is subject
30
+ to applicable law.
31
+
32
+ ## Patents
33
+
34
+ The licensor grants you a license, under any patent claims the licensor can
35
+ license, or becomes able to license, to make, have made, use, sell, offer for
36
+ sale, import and have imported the software, in each case subject to the
37
+ limitations and conditions in this license. This license does not cover any
38
+ patent claims that you cause to be infringed by modifications or additions to
39
+ the software. If you or your company make any written claim that the software
40
+ infringes or contributes to infringement of any patent, your patent license for
41
+ the software granted under these terms ends immediately. If your company makes
42
+ such a claim, your patent license ends immediately for work on behalf of your
43
+ company.
44
+
45
+ ## Notices
46
+
47
+ You must ensure that anyone who gets a copy of any part of the software from you
48
+ also gets a copy of these terms.
49
+
50
+ If you modify the software, you must include in any modified copies of the
51
+ software prominent notices stating that you have modified the software.
52
+
53
+ ## No Other Rights
54
+
55
+ These terms do not imply any licenses other than those expressly granted in
56
+ these terms.
57
+
58
+ ## Termination
59
+
60
+ If you use the software in violation of these terms, such use is not licensed,
61
+ and your licenses will automatically terminate. If the licensor provides you
62
+ with a notice of your violation, and you cease all violation of this license no
63
+ later than 30 days after you receive that notice, your licenses will be
64
+ reinstated retroactively. However, if you violate these terms after such
65
+ reinstatement, any additional violation of these terms will cause your licenses
66
+ to terminate automatically and permanently.
67
+
68
+ ## No Liability
69
+
70
+ *As far as the law allows, the software comes as is, without any warranty or
71
+ condition, and the licensor will not be liable to you for any damages arising
72
+ out of these terms or the use or nature of the software, under any kind of
73
+ legal claim.*
74
+
75
+ ## Definitions
76
+
77
+ The **licensor** is the entity offering these terms, and the **software** is the
78
+ software the licensor makes available under these terms, including any portion
79
+ of it.
80
+
81
+ **you** refers to the individual or entity agreeing to these terms.
82
+
83
+ **your company** is any legal entity, sole proprietorship, or other kind of
84
+ organization that you work for, plus all organizations that have control over,
85
+ are under the control of, or are under common control with that organization.
86
+ **control** means ownership of substantially all the assets of an entity, or
87
+ the power to direct its management and policies by vote, contract, or
88
+ otherwise. Control can be direct or indirect.
89
+
90
+ **your licenses** are all the licenses granted to you for the software under
91
+ these terms.
92
+
93
+ **use** means anything you do with the software requiring one of your licenses.
94
+
95
+ **trademark** means trademarks, service marks, and similar rights.
package/README.md ADDED
@@ -0,0 +1,224 @@
1
+ [![License: Elastic License v2](https://img.shields.io/badge/license-Elastic%20v2-0077B5.svg)](LICENSE)
2
+ [![Status: Active build](https://img.shields.io/badge/status-active%20build-2EA44F.svg)](https://github.com/twentytwohundred/wiki/blob/main/03-epic-map.md)
3
+ [![Tests: 1849 passing](https://img.shields.io/badge/tests-1849%20passing-2EA44F.svg)](.github/workflows/ci.yml)
4
+ [![Wiki](https://img.shields.io/badge/wiki-knowledge%20base-0077B5.svg)](https://github.com/twentytwohundred/wiki)
5
+ [![Built in public](https://img.shields.io/badge/built-in%20public-2EA44F.svg)](https://github.com/twentytwohundred/wiki/tree/main/handoffs/hobby)
6
+
7
+ # 2200
8
+
9
+ > A platform for hosting your fleet of always-on Agents.
10
+
11
+ 2200 is the runtime where your Agents live. They check email, manage calendars, watch portfolios, write code, file invoices ... whatever you outfit them to do. They run continuously, ask you questions when blocked, and resume when you answer. Each Agent has its own Identity, its own memory, its own tools, its own SCUT cross-instance identity, and its own pub for talking to the other Agents on your box.
12
+
13
+ This is "fleet operations, not chat."
14
+
15
+ This repository holds the runtime code. The full project knowledge base ... vision, architecture, decisions, conventions, per-epic specs, prior-art analysis, and the daily build handoffs ... lives in the public **[wiki repo](https://github.com/twentytwohundred/wiki)**.
16
+
17
+ ## Install
18
+
19
+ 2200 ships as a single CLI binary. macOS (arm64 / x86_64) and Linux (arm64 / x86_64), Node 22 or newer.
20
+
21
+ ```bash
22
+ # Shell installer (recommended for cold visitors):
23
+ curl -fsSL https://2200.ai/install.sh | sh
24
+
25
+ # npm directly (if you already have Node):
26
+ npm install -g @twentytwohundred/2200-cli
27
+ ```
28
+
29
+ Then run:
30
+
31
+ ```bash
32
+ 2200
33
+ ```
34
+
35
+ The bare `2200` invocation drops a fresh installation into a guided one-time setup: it initializes `2200_HOME` (default: `~/.local/share/2200/`), starts the supervisor daemon, mints your user identity, **offers Grok subscription sign-in** (if you have a SuperGrok or X Premium+ subscription, one click and your whole fleet uses Grok with no API key), and points you at `2200 agent build` to create your first Agent. The Agent wizard will let you pick from the providers you've set up (Anthropic, OpenAI, xAI / Grok subscription, xAI API key, DeepSeek, OpenRouter, Gemini, Kimi, or a local endpoint).
36
+
37
+ ### Grok-First
38
+
39
+ If you already pay for SuperGrok or X Premium+, you do not need an `XAI_API_KEY`. The bare-`2200` wizard offers sign-in inline; you can also do it any time from Settings → "Sign in with X / SuperGrok" or from the CLI:
40
+
41
+ ```bash
42
+ 2200 oauth xai login # device-code flow; print code + URL, poll
43
+ 2200 oauth xai status # show current credential + expiry
44
+ 2200 oauth xai logout # delete the local token (does not revoke at xAI)
45
+ ```
46
+
47
+ The OAuth credential is fleet-wide: one sign-in covers every Agent in your fleet whose model is set to `xAI / Grok (SuperGrok subscription)` in the picker. The legacy API-key path (`xai`, reading `XAI_API_KEY`) stays available as a separate, parallel provider for anyone who prefers metered access. See [the Grok-First decision record](https://github.com/twentytwohundred/wiki/blob/main/decisions/2026-05-21-xai-grok-oauth.md).
48
+
49
+ ### Update
50
+
51
+ ```bash
52
+ 2200 update # check the registry, prompt, install, restart the daemon
53
+ 2200 update --check # just report whether a newer version is available
54
+ 2200 update --yes # install without the confirm prompt (for scripted updates)
55
+ ```
56
+
57
+ `2200 update` only replaces the global package binary; your 2200_HOME state is never touched.
58
+
59
+ ### Uninstall
60
+
61
+ ```bash
62
+ npm uninstall -g @twentytwohundred/2200-cli
63
+ rm -rf ~/.local/share/2200/ ~/.config/2200/
64
+ ```
65
+
66
+ Doing the npm uninstall without the `rm` lines is safe ... your fleet data remains on disk and a reinstall picks it up.
67
+
68
+ ### Windows
69
+
70
+ Use [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install). Native Windows is not on the v0.1 support matrix.
71
+
72
+ ## Where to start
73
+
74
+ If you are new, read these in the wiki, in order:
75
+
76
+ 1. **[Vision](https://github.com/twentytwohundred/wiki/blob/main/01-vision.md)** ... what 2200 is, who it is for, why it exists.
77
+ 2. **[Architecture](https://github.com/twentytwohundred/wiki/blob/main/02-architecture.md)** ... object model, runtime shape, how OpenPub and SCUT compose underneath.
78
+ 3. **[Epic map](https://github.com/twentytwohundred/wiki/blob/main/03-epic-map.md)** ... the epic plan with scope, done-when, and dependencies.
79
+ 4. **[Seed team](https://github.com/twentytwohundred/wiki/blob/main/04-seed-team.md)** ... who is building this, how they coordinate, when they migrate.
80
+
81
+ Then follow the [conventions](https://github.com/twentytwohundred/wiki/tree/main/conventions/) to understand how the wiki itself is structured (it dogfoods the same Brain pattern that 2200's Agents use for their own memory).
82
+
83
+ ## Status
84
+
85
+ **Active build, in public.** Live as of 2026-05-19.
86
+
87
+ What's shipped on `main`:
88
+
89
+ - **Agent runtime kernel** ... persistent supervisor + per-Agent processes, scheduler, brain (SQLite FTS5), tools, audited credential vault, structured logging, cost caps + per-Agent budgets. [[02-architecture]]
90
+ - **Local pub coordination** ... multi-Agent messaging on a shared box via OpenPub. Ambient routing, @-mentions, `@team` broadcast, anti-ack-spiral guards. Multi-Agent coordination has been running end-to-end for weeks.
91
+ - **Nine LLM providers wired** through a single provider abstraction: Anthropic (native Messages API), OpenAI, DeepSeek, Kimi (Moonshot), xAI (API key), **xAI / Grok via SuperGrok subscription (OAuth, no API key)**, OpenRouter, Gemini, plus `local` for self-hosted endpoints (Ollama, LM Studio, vLLM, llama.cpp). The subscription path is the Grok-First positioning ... see the section above.
92
+ - **SCUT cross-instance identity** ... every Agent gets a verifiable identity at creation time. Hosted minter at `register.openscut.ai` for the default path; self-hosted SCUT for advanced operators.
93
+ - **Conversational onboarding** ... the wizard interviews you about an Agent you want to build, then materializes the Identity, suggests tools, suggests schedules, and auto-applies a curated Capability set. The interview transcript carries through to the new Agent's first brain note.
94
+ - **Capability Catalog** ([Phase F](https://github.com/twentytwohundred/wiki/blob/main/epics/14-phase-f-capability-catalog.md)) ... 13 first-party Capability entries on `main` (Gmail, Calendar, Drive, Slack, Discord, Telegram, GitHub, the major LLM providers, 1Password, Twilio, Stripe). Schema-validated frontmatter, walkthrough runner that drives credential prompts structurally, operator-override picker in the wizard, gap tracker that auto-files demand signals when the interview surfaces an intent the catalog can't satisfy.
95
+ - **Web app** ([Epic 15](https://github.com/twentytwohundred/wiki/blob/main/epics/15-web-app.md)) ... React + theme-aware design system. Fleet (Mission Control layout), Agent detail (Identity Card), Inbox (Keyboard Triage), Studio (multi-Agent pub canvas), Onboarding wizard, ⌘K command palette, Settings, Endpoints.
96
+ - **Live gateways** ... Discord and WhatsApp gateways are live; Slack and Telegram are catalog-ready.
97
+ - **Restart authority model locked.** Agents can restart themselves (`restart_self`); cross-Agent restart without operator approval is structurally impossible. See [agent-restart-authority](https://github.com/twentytwohundred/wiki/blob/main/decisions/2026-05-18-agent-restart-authority.md).
98
+ - **48 architecture decision records** and **11 conventions** locked. Prior-art surveyed (Hermes Agent, OpenClaw, Logseq, Trilium, Joplin, Cytoscape.js, react-markdown, remark-wiki-link, SilverBullet, Quartz, Foam, EdgeClaw, OCMT, OpenAEON, AnyClaw, mimiclaw) with license analysis.
99
+
100
+ **1849 tests passing** across the two workspace packages: 1754 runtime + 95 web. `pnpm verify:all` clean on every PR via [CI](.github/workflows/ci.yml).
101
+
102
+ The **Cray test** ... Hobby's actual migration into 2200 from Claude Code ... is the parallel track to the substrate work. The **launch moment** is David: when 2200 spawns its first Agent end-to-end through the wizard and that Agent does real work as a member of the team, the project ships. See [03-epic-map](https://github.com/twentytwohundred/wiki/blob/main/03-epic-map.md) for the full plan.
103
+
104
+ ## Who is building this
105
+
106
+ Three Agents and a product lead, the seed team:
107
+
108
+ - **Hobby** ... primary build Agent. Writes spec and code. Currently runs as Claude Code on Doug's MacBook; migrates into 2200 on the Cray test.
109
+ - **Simon** ... DevOps. Owns infrastructure: provisioning, DNS, TLS, backups, deployment.
110
+ - **Poe** ... OpenPub specialist. Part-time on 2200 until OpenPub v0.3.1 ships.
111
+ - **Doug Hardman** (MrDoug) ... product lead.
112
+
113
+ David is not on the seed team. David is the first Agent 2200 will spawn through its own conversational onboarding flow. See [04-seed-team](https://github.com/twentytwohundred/wiki/blob/main/04-seed-team.md).
114
+
115
+ The daily handoffs at [`wiki/handoffs/hobby/`](https://github.com/twentytwohundred/wiki/tree/main/handoffs/hobby) are the build log: every working day Hobby writes what was shipped, what's open, what's parked, what's coordinated with whom. The work is visible.
116
+
117
+ ## Repository contents
118
+
119
+ | Path | Purpose |
120
+ | ------------------------ | ------------------------------------------------------------ |
121
+ | `LICENSE` | Elastic License v2 |
122
+ | `README.md` | this file |
123
+ | `AGENTS.md` | conventions for Agents working in this repository |
124
+ | `SECURITY.md` | responsible disclosure |
125
+ | `CONTRIBUTING.md` | contribution model (seed-team-closed during the build phase) |
126
+ | `CHANGELOG.md` | release notes (populated when versioned releases start) |
127
+ | `THIRD_PARTY_NOTICES.md` | attribution for any code-lifts |
128
+ | `.github/` | issue templates, PR template, CI workflows |
129
+ | `src/` | runtime code (224 TypeScript modules) |
130
+ | `tests/` | test code (142 test files, 1754 runtime tests) |
131
+ | `apps/web/` | web app (Epic 15) ... React + Vite, theme-aware |
132
+ | `scripts/` | build, deploy, sync, and ops scripts |
133
+
134
+ ## Development
135
+
136
+ TypeScript monorepo with two pnpm workspaces: the runtime at the project root and the web app at `apps/web/`. Node 22+ required (see [`.nvmrc`](.nvmrc)).
137
+
138
+ ```bash
139
+ # install dependencies (one-time)
140
+ pnpm install
141
+
142
+ # common dev commands (runtime workspace)
143
+ pnpm typecheck # tsc --noEmit
144
+ pnpm lint # eslint . (flat config; type-aware rules)
145
+ pnpm lint:fix # auto-fix what's auto-fixable
146
+ pnpm format # prettier --write .
147
+ pnpm format:check # prettier --check . (used by CI)
148
+ pnpm test # vitest run
149
+ pnpm test:watch # vitest in watch mode
150
+ pnpm test:coverage # vitest with v8 coverage
151
+ pnpm build # tsup -> dist/
152
+ pnpm clean # remove dist, coverage, .tscache
153
+
154
+ # everything CI runs, in order, for both workspaces
155
+ pnpm verify:all
156
+ ```
157
+
158
+ CI runs on every PR and on `main` pushes (see [.github/workflows/ci.yml](.github/workflows/ci.yml)). Type-check, lint, format check, test, build, for both workspaces. All must pass before merge. Branch protection requires CI green; self-merge is the workflow during the seed-team build.
159
+
160
+ ### Toolchain
161
+
162
+ Each pick is documented in the wiki [decisions/](https://github.com/twentytwohundred/wiki/tree/main/decisions) folder.
163
+
164
+ - **Language:** TypeScript with strict + type-aware ESLint rules
165
+ - **Build:** [`tsup`](https://tsup.egoist.dev/) (esbuild-based, sensible defaults for CLIs and libraries)
166
+ - **Test:** [`vitest`](https://vitest.dev/)
167
+ - **Lint:** [`eslint`](https://eslint.org/) with [`typescript-eslint`](https://typescript-eslint.io/) flat config; `strictTypeChecked` + `stylisticTypeChecked` recommended sets
168
+ - **Format:** [`prettier`](https://prettier.io/) (no semicolons, single quotes, trailing commas, 100-char width)
169
+ - **Package manager:** [`pnpm`](https://pnpm.io/)
170
+ - **Web framework:** React 19, Vite, theme-aware design tokens generated from `tokens.json`
171
+
172
+ ### Project layout (high level)
173
+
174
+ ```
175
+ src/runtime/
176
+ ├── agent/ Agent process boundary (bootstrap, loop, sandbox)
177
+ ├── llm/ provider abstraction (8 vendors + local)
178
+ ├── pub/ OpenPub integration, ambient routing, anti-ack guards
179
+ ├── brain/ per-Agent + shared Brain (SQLite FTS5)
180
+ ├── credentials/ audited vault, credential_request surface
181
+ ├── onboarding/ conversational interview + Capability catalog + walkthroughs
182
+ ├── supervisor/ fleet supervisor, scheduler, control plane
183
+ ├── http/ HTTP API the web app drives
184
+ ├── connectors/ Discord, WhatsApp, Slack, Telegram gateways
185
+ ├── tools/ baseline tool registry (built-in tools)
186
+ ├── secrets/ SecretRef resolution + sealed storage
187
+ └── ...
188
+ apps/web/src/
189
+ ├── screens/ Fleet, Agent, Inbox, Studio, Settings, Onboarding, ...
190
+ ├── primitives/ Pill, Card, Button, Tag, ...
191
+ ├── palette/ ⌘K command palette
192
+ ├── theme/ theme switcher + token plumbing
193
+ └── ...
194
+ ```
195
+
196
+ ## License
197
+
198
+ [Elastic License v2](LICENSE). Source-available. Use, copy, distribute, and create derivative works are permitted; hosting as a managed service to third parties and license-key tampering are prohibited.
199
+
200
+ Prior-art surveyed in the wiki has been license-checked. See [License posture](AGENTS.md#license-posture) in `AGENTS.md` and [license-posture](https://github.com/twentytwohundred/wiki/blob/main/conventions/license-posture.md) in the wiki for the discipline applied to any code-lift. Attributions live in [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).
201
+
202
+ ## Security
203
+
204
+ See [SECURITY.md](SECURITY.md) for responsible disclosure.
205
+
206
+ A deeper read on what's a structural security boundary in 2200 vs what's a heuristic ... [heuristics-vs-boundaries](https://github.com/twentytwohundred/wiki/blob/main/decisions/2026-05-18-heuristics-vs-boundaries.md) ... is the public posture.
207
+
208
+ ## Contributing
209
+
210
+ The seed team is closed during the build phase. After launch, see [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution model.
211
+
212
+ ## Cross-references
213
+
214
+ - **Project domain:** [2200.ai](https://2200.ai)
215
+ - **GitHub org:** [github.com/twentytwohundred](https://github.com/twentytwohundred)
216
+ - **Wiki (knowledge base):** [twentytwohundred/wiki](https://github.com/twentytwohundred/wiki)
217
+ - **Daily build handoffs:** [`wiki/handoffs/hobby/`](https://github.com/twentytwohundred/wiki/tree/main/handoffs/hobby)
218
+ - **License:** [Elastic License v2](LICENSE)
219
+
220
+ ---
221
+
222
+ _Built in public. Ship when ready._
223
+
224
+ 2200 is developed by TWENTYTWOHUNDRED LLC. Licensed under the Elastic License v2.0.
@@ -0,0 +1,31 @@
1
+ # Third-party notices
2
+
3
+ This file lists code lifted into 2200 from external projects, along with the upstream license and the portions covered.
4
+
5
+ Empty for now. Per the [License posture section in AGENTS.md](AGENTS.md#license-posture), every code-lift gets recorded here with:
6
+
7
+ - Source project, URL, and license
8
+ - Specific files or functions lifted
9
+ - Original copyright notice (preserved)
10
+ - Brief note on what was changed, if anything
11
+
12
+ ## Format template
13
+
14
+ When a code-lift happens, add an entry like the following:
15
+
16
+ ```
17
+ ## <Source project>
18
+
19
+ - **URL:** https://github.com/<org>/<repo>
20
+ - **License:** <SPDX identifier>
21
+ - **Lifted:** <files or functions>
22
+ - **Original copyright:** Copyright (c) <year> <holder>
23
+ - **Notes:** <what changed, why we lifted, what we adapted>
24
+ ```
25
+
26
+ ## Pattern lifts (no obligation, listed for credit)
27
+
28
+ These are architectural patterns lifted by understanding rather than by code copy. Not legally required to list, but credit is given where credit is due.
29
+
30
+ - **OpenClaw** (MIT, Copyright 2025 Peter Steinberger): supervisor model, plan/run/perm wrapping discipline, Skills runtime model, baseline tool shape, profile/state-dir affordance, BOOT.md per-Agent ritual.
31
+ - **Perplexity Computer** (closed source, public materials only): "always-on helpful Agent" UX shape, integration health monitoring patterns.