One telemetry deck, five host plugins, and a hard rule: the screen never says anything the data cannot prove.
A position: most agent dashboards are optimistic fiction — green badges with no probe behind them, leaderboards built on three samples, "97% healthy" strings typed by hand. AgOS takes the opposite bet: an agent operating system becomes trustworthy exactly when its UI is forbidden to decorate. Every number on screen is derived from a ledger on disk; every missing field renders as “not collected” instead of a made-up zero; every model-driven suggestion is recorded before it is trusted, shadowed before it is wired in.
The 2026-09-08 agent design is the product contract: humans keep authority; models propose; memory / skills / assemble share one four-stage loop; secrets have one classifier; allocation is ranking only. The in-repo source of truth is docs/AGENT.md.
AgOS is a single-user Agent OS layer for the DeepSeek Harness (DSH) runtime. It replaces the stock web UI with a full telemetry deck — multimodal chat, sub-agent lineage, a homelab machine fleet, model routing, skills, plans, and a memory workbench — backed by five DSH plugins that expose everything as auditable JSONL ledgers and typed HTTP routes.
The project explores one question end to end: what does an agent cockpit look like if fabrication is a build error? The answer has four layers.
- UI — repo-wide TypeScript AST scanners fail the build when a screen sentence is not computed from the payload it describes, when a
/api/agos/routes*write appears outside one quarantined file, or when a banned verdict literal sneaks back in. - Authority — the live route selector
POST /api/agos/routes/decideexists on the host and is unreachable from the SPA by construction. Assemble, skill shortlists, and memory inject never switch the live session model and never start a swarm. - Closed loops — memory, skills, and model allocation share the same four stages: candidates → rank → expose → operator-confirmed feedback. Exposure is not a win. A missing query is not relevance zero.
- Heuristics with a ruler — the session-memory extractor ships with a labeled corpus and a per-sample regression gate. A rule edit that breaks any previously-passing sample turns the suite red.
None of this is style guidance. Each rule in §2 names the test that enforces it.
- 1. Problem Statement
- 2. The Honesty Contract
- 3. Agent Design
- 4. System Architecture
- 5. The Twelve Surfaces
- 6. HTTP API Reference
- 7. The Data Layer: Ledgers on Disk
- 8. Shadow Routing
- 9. Session Memory and the Ruler
- 10. Verification Infrastructure
- 11. Getting Started
- 12. Development
- 13. Limitations
- License & Credits
- Decorated state. A status pill says "healthy" because a designer chose green, not because a probe returned. The sentence on screen is a string constant; the data it claims to summarize was never consulted.
- Invented zeros. A field the collector never captured renders as
0,false, or an empty bar — indistinguishable from a measured zero. Absence of evidence is silently rendered as evidence of absence. - Suggestions obeyed before measured. A model picks the "best" agent/machine/skill and the UI wires the pick straight into execution. Nobody ever learns how often the picker would have been wrong, because the human's counterfactual choice is never recorded alongside.
All three failure modes are mechanically detectable, so all three should be build errors — enforced by static locks and unit gates, not by review-time vigilance. AgOS is a working implementation of that proposition on top of a real agent runtime, driving a real multi-machine homelab, with every screen backed by an append-only ledger a human can cat.
These are not style guidelines — each is enforced by a test that fails the build.
- On-screen claims must be computed from on-screen data. Sentences about a dataset are functions of the payload, never string constants. Enforced by derived-copy locks that read sibling component source and assert banned verdict literals absent (
routes-model.test.ts,console-live.test.ts,council-ledger-model.test.ts), and by SSR content assertions that render components with controlled payloads and check the emitted copy. - Absent ≠ zero ≠ false. Every nullable telemetry field is typed
number | undefinedandundefinedrenders as “未采集” (not collected) — a first-class UI state with its own copy. Overview sources carry a three-state header (ready / stale / absent); the empty state "nothing pending" is only allowed to render when all sources areready. - Route writes are quarantined; decide is banned. Mutating
/api/agos/routes*fetchcalls live in exactly one file (routes-assemble.ts), checked by a repo-wide AST lock: five literal URLs, no aliasing, no concatenation, no template assembly. The string/api/agos/routes/decideis banned across the frontend source tree. Other confirm-gated writes (skills, session memory, memory desk) live in their own*-api.tsmodules and are not added to that routes whitelist. - Suggestions are recorded, not obeyed. The LLM route selector runs in shadow mode (§8): one call per dispatch review, written to the ledger with the human's actual choice alongside — agreement is measured, never assumed. Outcome backfill only happens when the suggested machine actually ran the batch.
- Heuristics carry a ruler. The session-memory extractor ships with a labeled corpus, per-sample pass baselines, and an
acceptEditgate (§9). - Security gates are tested as gates. The media route confines reads to a realpath-checked attachments root and sniffs magic bytes. Fleet artifact retrieval validates run IDs and relative paths before any SSH command is composed. Secrets have one classifier (§3.3).
Canonical text: docs/AGENT.md. This section is the public restatement.
The operator is the execution authority. Models only propose. POST /api/agos/routes/decide is unreachable from the SPA. Assemble, shadow routing, skill shortlists, and memory inject do not switch the live session model and do not start a swarm.
- Candidates — this session's store / this turn's catalog / the role's model pool. IDs outside the list are not invented.
- Rank — lexical match (ASCII tokens ≥ 2, CJK whole-word runs ≥ 2, substring; single CJK characters are dropped) plus a Beta-Bernoulli posterior (κ = 4, unlisted prior = 0.15). An empty query or zero overlap falls back to importance and must say “not relevance”.
- Expose — shortlist K = 8. Inject, catalog trim, and assemble proposals are impressions, not wins.
- Feedback — JSONL is written only after the operator confirms. A
skill()call, an inject impression, and a three-role trial are notok/fail.
No embeddings, two-tower models, collaborative filtering, or fake CTR. The posterior never feeds live dispatch.
If a lexical shortlist drops a constraint, the highest-importance constraint is reserved into the list with method: 'constraint-reserve' and lexical = 0.
Implementation: plugins/dsh-agos/lib/secrets-gate.js. Other plugins import it; they do not keep a weaker regex.
| Disposition | Where | Behavior |
|---|---|---|
| Refuse persist | session memory, pins, route previews | drop the whole candidate and increment a counter. Fragments are not stored. |
| Redact then persist | fleet / route-outcome ledgers | replace credential material with «redacted». Paths and environment names stay. |
Implementation: plugins/dsh-agos/lib/allocate-kernel.js. Skill evolve, memory shortlists, and assemble rankAgents share prior / posterior math. Three ledgers stay separate: skill-allocate.jsonl, memory-relevance.jsonl, route-outcome.jsonl. Shadow rows do not enter the allocation posterior.
Implementation: plugins/dsh-agos/lib/agent-prompts.js. Selector, skill rerank, memory reminder, assemble planner / implementer / reviewer, fleet guidance, and the autonomous-optimize sub-agent all start from the same preamble: use only given facts, do not invent IDs, do not write decide, write absence as not collected.
If the implementer emits a tool call, dispatch retries once with tools forbidden. A second failure stays a failure — no invented final draft. The reviewer sees only the implementer final, never the planner draft.
No Conductor / TRINITY training. Assemble does not become a swarm. The first win/loss row is not invented for verification. The desktop .app is not treated as the 0.1.2 runtime. AgOS does not write Fleet Memory / MEMORY.md and does not run fleet-memory-push.sh.
flowchart LR
subgraph Browser
SPA["frontend/ · Vite + React SPA<br/>(served at /agos/)"]
end
subgraph DSH host process
AGOS["dsh-agos<br/>console · skills · session memory · SPA server"]
ROUTER["dsh-agos-router<br/>selector · assemble · shadow · outcome ledger"]
CN["cn-capabilities<br/>vision council · ASR · media gate · usage"]
FLEET["dsh-fleet<br/>hosts · dispatch · wake · batches"]
MCP["dsh-mcp-bridge<br/>agos_* MCP tools"]
end
subgraph Disk
LEDGERS[("JSONL ledgers<br/>route-outcome · fleet runs · council · plans · audit")]
end
SPA -->|typed HTTP + mux frames| AGOS & ROUTER & CN & FLEET
ROUTER --> LEDGERS
FLEET --> LEDGERS
CN --> LEDGERS
AGOS --> LEDGERS
MCP -->|loopback HTTP| AGOS
Two deliberate coupling rules shape the design:
- Plugins couple through files, not runtime mutation. Cross-plugin data flows through shared ledger files on disk. Shared kernels (prompts, secrets, allocation) are imported from
dsh-agosso there is one copy of each rule. - The SPA is served from disk per request.
dsh-agosservesfrontend/distwith SPA fallback on every request, so frontend edits never require a host restart. Plugin JS is copied into the profile — not symlinked — and a plugin edit needs a host restart.
| Plugin | Role |
|---|---|
dsh-agos |
Console core: OS-level control panel, skills audit/studio/evolve/trim, overview, session metadata, session trash, session-memory store + inject + relevance, memory desk, turn-evidence, plugin inventory, SPA static server. |
dsh-agos-router |
Model routing: LLM selector over CN candidates, rule fallback, route-outcome JSONL, allocation posterior feeding planner/implementer/reviewer assemble(), confirm-gated text-only dispatch, shadow selector. |
cn-capabilities |
CN-model capability layer: 19 registered tools, vision, speech, image generation, delegation, multi-model council with a blind arbiter, plan_run store, browser/CLI tools, read-only usage metering. |
dsh-fleet |
Homelab multi-machine concurrency: remote dsh --profile headless over ssh+stdin, in-process local subagents, opt-in Codex SDK host, wake-on-LAN, health probes, per-host limits, reroute, artifact retrieval, scrubbed event ledger. |
dsh-mcp-bridge |
Minimal MCP Streamable HTTP server (protocol 2025-03-26) at POST /mcp, with five tools: agos_sessions, agos_prompt, agos_result, agos_swarm_status, agos_memory_search. Only agos_prompt starts real model work. |
Key modules:
dsh-agos—lib/agent-prompts.js·lib/allocate-kernel.js·lib/secrets-gate.js·lib/session-memory-rank.js·lib/session-memory-inject.js·lib/turn-evidence.js·lib/memory-desk.js·lib/skills-evolve.jsdsh-agos-router—lib/selector-llm.js·lib/allocation-score.js·lib/assemble.js·lib/dispatch.js·lib/shadow.js·lib/sanitize.jscn-capabilities—lib/index.js·lib/council-record.js·lib/usage.mjsdsh-fleet—lib/fleet-runtime.mjs·lib/fleet-ledger.mjs·lib/fleet-dispatch.mjs·lib/fleet-artifacts.mjs
agos/
├── frontend/ # Vite + React SPA (TypeScript, node:test via tsx)
│ ├── src/pages/ # ChatPage · ConsolePage · MemoryGraphPage · SettingsPage
│ ├── src/components/ # chat/ console/ fleet/ graph/ lineage/ layout/ ui/
│ ├── src/contract/ # vendored DSH host API contract (pinned)
│ ├── src/stores/ # mux client, live session stores (additive only)
│ ├── src/fold/ # transcript fold engine + replay invariants
│ └── UPSTREAM.pin # pinned upstream contract version
├── plugins/
│ ├── dsh-agos/ # console core + SPA server + agent kernels
│ ├── dsh-agos-router/ # routing, ledger, shadow selector
│ ├── cn-capabilities/ # vision / speech / council / plans / usage
│ ├── dsh-fleet/ # homelab fleet dispatch
│ └── dsh-mcp-bridge/ # MCP Streamable HTTP bridge
├── docs/AGENT.md # agent / prompt / memory / secrets / allocation contract
├── regression/ # OpenCLI browser regression + macOS app shell (Swift)
├── scripts/ # iterate.sh · deploy-plugins.sh · dev-links.sh · test-all.sh
└── docs/media/ # banner and static assets
Do not edit frontend/src/fold, frontend/src/api-client, frontend/src/contract, vite.config.ts, or package.json unless the host contract itself moved.
The SPA talks to the DSH host through a typed API contract membrane at frontend/src/contract/api/ pinned by UPSTREAM.pin (deepseek-harness @ a66e470204, 0.1.2-rc.1). npm run verify includes vendor:diff, which compares that pin git object (read-only git show / git archive) — not another checkout's live HEAD. Wire constants (REMOTE_STREAM_MUX_PATH = /api/remote.mux, $events endpoints) must be byte-equal to the pin; all 19 adapter contents are frozen to reviewed base blobs by contract-baseline.sha256. This is a regression guard, not full type-compatibility proof; the membrane is an adapter set, not a wholesale dump of later packages/host/apiproxy/src/api. Do not silently upgrade the harness or move the pin.
| Consumed source | Produced by | Used for |
|---|---|---|
/api/remote.mux (one route name; the client still opens one WebSocket per logical stream), /api/$events/result, session RPCs |
DSH host core | Chat transcript, approvals, session matrix |
/api/swarm/progress, /api/swarm/history |
swarm plugin (external) | Lineage tree and history |
/api/trace/sessions |
trace plugin (external) | Trace time-share bars |
/api/memory/* (graph, search, link-suggestions) |
memory plugin (external) | Memory workbench graph |
| Permission-adjudication audit JSONL | mode-alignment component (external) | Permission-verdict annotations |
Host civ memory_submit |
host tools (optional) | Fleet Memory writes from the memory desk. Unwired → CIV_UNAVAILABLE. A generic tools.invoke is not evidence the tool exists. |
| Local usage cache (SQLite + history JSON) | a menu-bar usage app (external) | Provider quota meters (read-only) |
The deck runs at http://127.0.0.1:3091/agos/. Twelve navigable surfaces: three top-level workspaces (Chat, Memory, Settings) plus nine console tabs.
Multimodal conversation with a session sidebar (pinned / recent / archived). Approvals are first-class UI. Permission-verdict annotations attach to tool cards. Voice input uses Web-Audio VAD and POST /api/cn/asr. Session delete moves to an audited trash. When /api/remote.mux is down, new-session disables with an explicit tooltip. The on-screen ReplayScrubber only slices the already-folded snapshot; it is not event replay.
Each turn can show a turn-evidence strip: memory inject impressions and skill-catalog trim for this turn only. Lanes are replaced, not deep-merged. Absence of a pre-step is “not collected”, not a fake zero. The strip does not invent the first useful / mis-recall row.
Backing: host mux + dsh-agos + cn-capabilities.
An attention inbox merged from four ledgers — lineage failures, pending route outcomes, skill drift, flagged council reviews — plus a session matrix and usage band. Each source is ready / stale / absent. “Nothing pending” may only render when all four sources are ready.
Backing: /api/agos/overview + swarm progress + routes ledger + council ledger.
Homelab fleet: reachability from SSH probe truth; power snapshots are intent, not evidence. Wake and sleep sit behind cost confirmation. Dispatch review runs the shadow selector (§8).
Backing: dsh-fleet + shadow endpoints of dsh-agos-router.
Live matrix of host sessions with running/queued/done lamps. Preset labels and descriptor labels stay semantically separate.
Backing: host session RPC + dsh-agos session metadata.
Sub-agent genealogy: live batches as a job tree plus per-day history. Duration “未采集” for non-finite values. The empty state names the missing ledger file.
Backing: swarm progress + swarm history ledgers.
Per-session LLM-vs-tool duration bars. Archived sessions get no attach button.
Backing: trace timeline route + dsh-agos session metadata.
Read-only archive of plan records. The words “只读数据源” and the backing endpoint are printed on the page.
Backing: cn-capabilities plan store + overview cross-check.
Skill registry audit and a proposal-only studio. Usage percentages refuse to render until their denominator is ready. Studio only proposes; every write is confirm-gated. Catalog trim is on by default and fails closed to the full catalog. A skill() call is not a win. Small-model rerank is opt-in (DSH_AGOS_SKILL_RERANK=1) and shows “unavailable” when the model cannot be reached.
Backing: dsh-agos skills routes + host RPC skill list.
Every model-routing decision as a ledger row, plus assemble / dispatch. Absent fields render “未采集”. Shadow rows have no manual outcome buttons. Assemble and dispatch each have their own confirm step. Dispatch is a text-only trial: it does not switch the live session, does not touch the repo, and does not write ok/fail unless a parseable reviewer verdict passes the attribution gates.
Backing: dsh-agos-router ledger routes.
Five heterogeneous ledgers normalized into seven-field result rows and a (source, taskType, model) coverage grid. Per-source vocabularies are never summed across sources.
Backing: the outcomes deriver in dsh-agos-router.
Multi-model image-review rounds. Disagreement highlights come only from the arbiter's disagreements array. Rounds with too few valid answers are inconclusive.
Backing: cn-capabilities council records + media route.
Memory — episodic / semantic / skill memory as a wikilink graph (atlas / ego-local / community / supersedes-lineage), plus a session-memory pane and a memory desk.
- Working set = search ∪ lexical overlap ∪ inspected, minus desk-voided slugs.
- Atlas pins the same union and does not relabel working-set pins as search hits. Desk-voided slugs are not pinned onto the atlas.
- Relevance feedback locks to this turn's inject query. An empty query renders “问句未采集,不能记相关”.
- Session memory is a convenience projection, not Fleet Memory. Desk promote/void writes
~/.dsh/agos/memory-desk/withfleetMemory: false. Submit requires a real hostmemory_submittool; otherwiseCIV_UNAVAILABLE.
Settings — read-only projection of host settings namespaces, plus a plugin inventory that does not claim a plugin is installed unless the profile copy is present.
48 API routes plus two static prefixes, registered by the five plugins. Default host: 127.0.0.1:3091.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/agos/overview |
Aggregate KPIs (soft dependencies — a missing source never 500s) |
| GET | /api/agos/session-meta |
Session metadata list (pin/archive state) |
| POST | /api/agos/session-meta/pin |
Pin / unpin a session |
| POST | /api/agos/session-meta/archive |
Archive / unarchive a session |
| GET | /api/agos/session-memory |
Extracted memory store for one session |
| POST | /api/agos/session-memory/pin |
Pin / unpin one extracted item (confirm-gated; secrets refused) |
| GET, POST | /api/agos/session-memory/inject |
Read inject switch / confirm-gated enable |
| GET, POST | /api/agos/session-memory/relevance |
Shortlist + operator useful / mis-recall (not a model call) |
| GET, POST | /api/agos/memory/desk |
Promote / void / civ-submit. fleetMemory stays false until civ accepts |
| GET | /api/agos/turn-evidence |
Last pre-step memory/skills evidence for one session |
| GET | /api/agos/plugins |
Profile plugin inventory (copy presence, not wishful install) |
| POST | /api/agos/session/delete |
Move a session to the audited trash |
| GET | /api/agos/session-trash |
Recoverable deleted-session list |
| GET | /api/agos/skills |
Skills catalog + audit (?refresh=1 re-scans) |
| GET | /api/agos/skills/studio |
Read one skill for the studio editor |
| POST | /api/agos/skills/draft |
Create a skill draft on disk |
| POST | /api/agos/skills/description |
Patch a skill description (confirm-gated) |
| GET, POST | /api/agos/skills/evolve |
Propose skill shortlist / record outcomes |
| GET, POST | /api/agos/skills/trim |
Catalog-trim switch (default on; fail-closed to full catalog) |
| GET | /api/agos/yolo-decisions |
Permission-adjudication audit rows |
| GET, HEAD | /agos (static prefix) |
Serve the SPA from frontend/dist |
| Method | Path | Purpose |
|---|---|---|
| GET | /api/agos/routes |
Recent routing-decision ledger entries |
| POST | /api/agos/routes/decide |
Live routing decision — unreachable from the UI by construction |
| GET | /api/agos/routes/outcomes |
Derived outcome rows across five ledgers |
| POST | /api/agos/routes/outcome |
Record one manual outcome (rejected on shadow rows) |
| POST | /api/agos/routes/annotate |
Append a human annotation |
| POST | /api/agos/routes/shadow |
Shadow selector — at most one model call; pick may be null |
| POST | /api/agos/routes/shadow/link |
Link a shadow record to the fleet batch that actually ran |
| GET, POST | /api/agos/routes/assemble |
Read latest assemble state / propose a team |
| GET, POST | /api/agos/routes/assemble/dispatch |
Read dispatch state / confirm-gated text-only trial (409 on mismatch) |
| Method | Path | Purpose |
|---|---|---|
| GET | /api/cn/council-records |
Structured council/review ledger |
| GET, POST | /api/cn/plans (prefix) |
List saved plans / edit a plan's goal and steps |
| GET | /api/usage/providers |
Provider quota from the local usage cache |
| GET, HEAD | /api/cn/media |
Sandboxed, magic-byte-sniffed artifact streaming |
| POST | /api/cn/asr |
Speech-to-text (base64 audio, 25 MB cap) |
| POST | /api/cn/vision |
Vision Q&A (base64 image, 12 MB cap) |
| Method | Path | Purpose |
|---|---|---|
| GET | /api/fleet/hosts |
Hosts with health, in-flight runs, power state |
| POST | /api/fleet/dispatch |
Dispatch a prompt to selected hosts (202) |
| GET | /api/fleet/batches |
List batches (?include=runs) |
| GET | /api/fleet/batch |
One batch's detail |
| POST | /api/fleet/cancel |
Cancel a batch or a single run |
| GET | /api/fleet/trace |
Page a run's live trace by physical line number |
| GET | /api/fleet/ws |
Browse a remote worker workspace / read one file |
| GET | /api/fleet/artifacts |
Artifact manifest for a run |
| GET | /fleet/artifact/… (static prefix) |
Stream one artifact file or a tgz over SSH |
| GET | /api/fleet/power |
Power state of all remote nodes |
| POST | /api/fleet/wake |
Wake named hosts |
| POST | /api/fleet/sleep |
Put one host to sleep (requires confirm) |
| POST | /api/fleet/preflight |
Reachability probe + smoke check |
| Method | Path | Purpose |
|---|---|---|
| POST | /mcp |
JSON-RPC MCP endpoint: agos_sessions · agos_prompt · agos_result · agos_swarm_status · agos_memory_search |
Everything the deck shows can be cat-ed. Writers scrub or refuse secrets before appending.
| File | Written by | Purpose |
|---|---|---|
~/.dsh/logs/route-outcome.jsonl |
dsh-agos-router |
Decisions, outcomes, annotations, shadow, assemble/dispatch |
~/.dsh/logs/fleet/runs.jsonl |
dsh-fleet |
Fleet run lifecycle + host power events |
~/.dsh/logs/council-record.jsonl |
cn-capabilities |
Council rounds with arbiter verdicts |
~/.dsh/logs/plans/plan-*.json |
cn-capabilities |
One JSON per plan |
| permission audit JSONL | mode-alignment (external) | Mode-escalation adjudication |
~/.dsh/agos/skill-allocate.jsonl |
dsh-agos |
Operator-confirmed skill useful / not-useful |
~/.dsh/agos/memory-relevance.jsonl |
dsh-agos |
Operator useful / mis-recall on exposed session-memory items |
~/.dsh/agos/turn-evidence.jsonl |
dsh-agos |
Last pre-step memory/skills evidence per session |
~/.dsh/agos/session-memory/*.json |
dsh-agos |
Per-session extracted memory (0600) |
~/.dsh/agos/session-memory-inject.json |
dsh-agos |
Inject on/off (default on) |
~/.dsh/agos/memory-desk/*.jsonl |
dsh-agos |
Promote / void / civ-submit. Not Fleet Memory |
~/.dsh/agos/delete.log |
dsh-agos |
Session-deletion audit |
- decision —
{id: dec-…, ts, taskType, role, candidates, pick, confidence, reason, source}. Shadow decisions addmode:'shadow'. kind:'outcome'—{ref, result:'ok'|'fail', at, source}.sourceismanual,fleet-end, orreviewer-verdict.ev:'annotate'/ev:'shadow-link'— notes and batch bindings.kind:'assemble'/kind:'dispatch'— latest proposal and latest trial. A dispatch row is not a decision and not an outcome.
One JSON document per session: items[] {kind: fact|constraint|preference|rejected, text ≤200 codepoints, importance 1–5, sourceTurn} plus skippedSensitive. Status may be ready, extracting, or degraded (show last confirmed items; do not render a failed extract as an empty shop). A read failure is “store unread”, not zero items.
The route selector is deliberately powerless. When you review a fleet dispatch, AgOS asks a small model which machine it would pick — then does nothing with the answer except write it down.
- Review — opening the dispatch confirm step triggers at most one
POST /api/agos/routes/shadow. The user's checkbox selection is not part of the selector's input. - Record —
mode:'shadow'.pickmay benullwhen the model fails — no fabricated first-candidate fallback. - Link — if the dispatch happens,
ev:'shadow-link'binds suggestion to batch. - Backfill — only if the suggested machine actually ran the batch.
Shadow rows are excluded from the allocation posterior. Manual outcome writes on shadow rows are rejected.
dsh-agos extracts durable user-stated facts, constraints, preferences, and rejections from session transcripts.
- Only direct user text on the browser/RPC channel is eligible.
- Questions, tables, code fences, and fragments are vetoed for all kinds; single-turn tool instructions are vetoed from becoming constraints.
- Secret patterns drop the candidate and increment a counter.
Inject (default on) prepends a fail-closed shortlist to the next turn. The reminder says this is a convenience projection, not Fleet Memory. Impressions are recorded on the turn-evidence lane. Useful / mis-recall is written only after the operator confirms against the locked inject query.
Four blocks, scored separately: RPC-channel user sentences, bare-source rows, known misreports (untuned; currently 3/8 fail and that baseline is not silently edited), and assistant sentences for rejected-alternative mining. The corpus is generated locally by mine.mjs and is not distributed. baseline.json stores per-sample pass IDs. Any previously-passing sample that regresses turns the suite red.
Counted on 2026-09-08 against this tree. Zero model calls.
| Package | Pass / Fail / Skip | Verification scope |
|---|---|---|
frontend/ |
365 / 0 / 1 | npm run verify: version, types, tests, build, pin and adapter-content guard |
plugins/dsh-agos |
154 / 0 / 2 | node --test test/*.mjs, includes three scaling checks |
plugins/dsh-agos-router |
91 / 0 / 0 | HTTP, feedback and shadow binding |
plugins/dsh-fleet |
137 / 0 / 0 | Full suite, real multiprocess locks and cleanup lifecycle |
plugins/cn-capabilities |
82 / 0 / 0 | Plans, isolated verification and real macOS sandbox |
plugins/dsh-mcp-bridge |
4 / 0 / 0 | Fake MCP |
| Total | 833 / 0 / 3 | Three private-corpus checks explicitly skipped; six additional browser component checks |
| Lock | Enforces |
|---|---|
| Routes write-endpoint whitelist | /api/agos/routes* writes only in routes-assemble.ts; five literals; decide banned across the tree |
| RoutesView no-network AST lock | Decisions view has no fetch/XHR/WebSocket and one sanctioned data hook |
| Three-tier badge ban | Removed trust-tier verdict literals may not reappear |
| Inbox single-source ban | Overview may not carry a hard-coded data-source claim |
| Council divergence lock | Divergence marks come from the arbiter's collected array |
| DispatchModal shadow source lock | Exactly one shadow call site; signature dedup pinned |
| Vendor contract vs pin object | vendor:diff loads a66e470204 from the harness git repo; live HEAD is not the baseline. Wire consts are BYTE_EQUAL; src/contract/api/* is a frozen adapter set |
regression/opencli-regression.sh drives a real Chrome through an OpenCLI bridge against the live deck — read-only, zero model calls. That historical live-host run was not repeated here. This round ran six real-Chrome component-fixture checks with synthetic data. Full commands, logs and limitations are in final verification; deployment dry-run still reports expected undeployed drift.
- A DSH host — DSH Desktop or
@deepseek-ai/dsh0.1.2-rc.1 (do not silently upgrade) - Node ≥ 22
- A DSH profile directory (
~/.dsh/profiles/<name>/)
git clone https://github.com/LeoLin990405/agos && cd agos
cd frontend && npm install && npm run build && cd ..
scripts/deploy-plugins.shPlugins deploy as copies, not symlinks. The host resolves @deepseek-ai/* from each plugin file's realpath, so plugins must live inside the profile tree.
Add the five plugins to your profile — file: dependencies in the profile's package.json, plus plugin entries in cordis.patch.yml:
# ~/.dsh/profiles/<profile>/cordis.patch.yml (excerpt)
- id: agos
- id: agos-router
- id: cn-capabilities
- id: fleet
config:
hosts:
- name: worker-1
kind: remote
ssh: user@worker-1
maxConcurrency: 2
- id: mcp-bridgeThen run the web host:
dsh --profile web --port 3091 --no-open
# → http://127.0.0.1:3091/agos/Desktop restart, when you need it, is nohup /bin/zsh ~/bin/dsh-desktop & on this machine. Do not treat the desktop .app as the 0.1.2 runtime.
scripts/iterate.sh # build → deploy → restart only if plugin bytes changed
scripts/iterate.sh --test # same, with the full red gate in frontFrontend-only edits: npm run build in frontend/. Plugin JS edits: rsync the profile copy and restart dsh.
scripts/dev-links.sh # once: gitignored node_modules links for in-repo plugin tests
scripts/test-all.sh # frontend verify + 5 plugin suites + deploy drift checktest-all.sh makes zero model calls and keeps the real exit code of npm run verify and each plugin node --test (grep is display-only). Private corpus tests read only an explicit SESSION_MEMORY_CORPUS_DIR; they were skipped this round. mine.mjs also requires an explicit input path. npm run replay needs AGOS_CORPUS (historical default: 392 trash sessions). Missing corpus is environment-unsatisfied, not a pass; do not copy a past “392 sessions passed” as this run’s result. There is no tracked .github/workflows.
The DSH host resolves @deepseek-ai/* upward from each plugin file's realpath. A symlink resolves from the link target — outside the profile tree — and fails with MODULE_NOT_FOUND. Desktop and web hosts additionally carry two different host package sets.
| Script | Behavior |
|---|---|
scripts/iterate.sh |
Optional gate → frontend build → deploy → conditional restart on port 3091 → health checks |
scripts/deploy-plugins.sh |
rsync -a --delete --checksum of the five plugins into desktop and web profile copies |
scripts/dev-links.sh |
Gitignored symlinks used only by in-repo plugin tests |
scripts/test-all.sh |
Frontend verify + five plugin suites + deploy drift check |
Stated plainly, in the spirit of the thing:
- Single-user, localhost-first. There is no auth layer of its own. Do not expose port 3091 to a network you don't trust.
- The memory workbench graph needs an external plugin. Without
/api/memory/*the Memory surface renders its quiet absent states. Session-memory extract/inject still works fromdsh-agos. - Fleet Memory submit is fail-closed. Host civ
memory_submitis not assumed present. A generictools.invokedoes not count as wired. Until the tool is actually registered, the desk staysCIV_UNAVAILABLEandfleetMemory: false. - The ruler measures fit, not generalization. Known-misreports still fail 3 of 8 rows that are textually indistinguishable from real constraints. That baseline is not silently edited.
- Shadow evidence accrues slowly. There is no synthetic replay. The first skill or memory win/loss row is not invented to make a chart look alive.
- Allocation does not dispatch. The posterior sorts assemble proposals and shortlists. It does not pick the live session model.
- Ledger scale is homelab scale. Fold-on-read over JSONL is fast for thousands of rows, not millions.
- CN-model tooling assumes CN providers. Adapting to other providers means editing
cn-capabilities. - Fleet lifecycle validation. The observed post-test ledger rename race was fixed and the complete 137-test Fleet suite passed this round. Real deployed dispatch remains outside that acceptance scope.
- MIT.
- The API contract under
frontend/src/contract/is an AgOS membrane aligned to deepseek-harness (MIT, © DeepSeek) pina66e470204.npm run vendor:diffchecks that pin object, not an arbitrary checkout HEAD. - Built to run on the DeepSeek Harness plugin runtime (
cordis); host packages (@deepseek-ai/*) are provided by your DSH installation. - The browser regression is driven through OpenCLI's browser bridge.
- Published from this tree as
LeoLin990405/agos.