Ozzy Dev — Product Architecture
Version: 0.7.0 Status: Canonical current-state architecture. Forward-facing plans live in the console at
/roadmap; superseded revisions live in `DECISIONS/`. Last updated: 2026-08-03 Owner:nexartis-ozzydev
Ozzy Dev is the Nexartis reference implementation of the on-machine agentic client. It is one product, and simultaneously the marquee case study for the whole Nexartis agentic stack: KnowYourModel, NANDA Node, Cubicle SDK, ABI Chat SDK, and the Nexartis fork of OpenCode.
1. Reason to exist
Ozzy Dev turns a developer's machine into a trusted, discoverable,
voice-driven agentic workstation. A single git clone plus one install
script gives a new engineer:
- A local runtime host (
local-macfirst;local-windowsandlocal-linuxfollow) that runs harnessed agents pulled from KnowYourModel. - A curated MCP tool catalog that gives those agents real capability — accessibility-tree desktop drive, web drive, memory, code context, KYM discovery, voice.
- A local console (SvelteKit) built on the ABI Chat SDK Svelte components, showing the currently active agent, its Cubicle spec, live turns, receipts, and the tool catalog.
- A first-party agent, "Ozzy", published in KYM, that ships as the default primary agent — with the option to fork, modify, and publish your own variant back to KYM.
Everything else — the agent harness, the security boundary, the agent registry, the discovery graph, the payment rails — is provided by an existing Nexartis SDK or service. Ozzy Dev composes them.
2. Product boundaries
Ozzy Dev is:
- The clone-and-install harness for the
local-mac,local-windows, andlocal-linuxCubicle runtime hosts. - The on-machine orchestrator: it discovers the machine, picks a runtime, picks an agent, compiles a Cubicle spec, launches a harness, and writes receipts back to KYM every turn.
- The MCP tool catalog manager on the machine.
- The identity anchor on the machine (Ed25519 keys, DID, keychain refs).
Ozzy Dev is not:
- Not a coding assistant for third-party editors. Cursor, Kilo, and Claude Code are unrelated products.
- Not Remote Control. Remote Control is a separate, opt-in bridge that lets an off-machine driver instruct Ozzy Dev. Kept decoupled because opening a socket to a relay is the moment a machine's security posture changes; that should be a discrete, revocable step.
- Not a wrapper around OpenCode's UX. Ozzy Dev uses OpenCode as its agent harness; Ozzy Dev is the product identity users see.
- Not a general MCP installer for the world. It curates the Nexartis blessed catalog for a Nexartis-ready workstation.
3. Mac Local Cubicle Architecture & Per-Workspace Governance
The Mac Local Cubicle completes the local macOS developer instance of the Nexartis agentic stack, pairing with the edge nexartis-my-cubicle-cube implementation:
- Edge vs Local Parity: While
my-cubicle-cubeexecutes inside Cloudflare Dynamic Workers / Durable Objects with Pegasus HB3 container integration,nexartis-ozzydevexecutes on macOS via supervised Node.js console services and stdio/HTTP native MCP engines (ozzydev-search,ozzydev-write,ozzydev-harness,ozzydev-voice). - Per-Workspace Scope: A single developer machine can host multiple independent workspaces (e.g.
20260802-ozzydev,20260730-my-cubicle-cube). Settings, privacy policies, autonomy constraints, and capability allowlists apply strictly on a per-workspace basis stored in D1 (workspace_cubicle_settingstable). - Privacy & Autonomy Levels:
privacy_level:'strict'(zero telemetry / local vector storage only),'standard'(PII pseudonymized in-flight),'permissive'(full context).autonomy_level:'full_autonomous'(direct execution),'semi_autonomous'(approval gates on deploy/publish),'manual_approval'(approval on every file write).local_vector_storage_only: Embeddings kept local incodesearch/chunkhoundwithout Zilliz sync.code_snippet_redaction: Sensitive tokens and code snippets redacted in turn receipts.
- KnowYourModel (KYM) Orchestrator Card Publishing:
- Integrates with KnowYourModel (
https://knowyourmodel.ai). - Exposes
POST /api/kym/publish-cardand Svelte 5<KymOrchestratorPublisher />component on/harnessto design, configure, and publish custom Orchestrator and Subagent Cards (nexartis:harness/orchestrator) directly to KYM. - Resolves role cards (
implementer,verifier,validator,researcher,orchestrator) dynamically at dispatch time viakym-resolver.ts.
- Integrates with KnowYourModel (
4. Host vs harness & Multi-Target Dispatch
@nexartis/cubicle-core already formalises the distinction, and Ozzy
Dev adopts it verbatim. See
`DECISIONS/ADR-001-host-and-harness.md`
for the decision record.
- Host = the deployment platform with its own security boundary and
platform APIs (
hb3,cloudflare-dynamic-worker,browser,device,home-hub,custom). Ozzy Dev addslocal-mac,local-windows,local-linux. - Harness = the agent engine that runs inside a host
(
claude-code,opencode). One host can support multiple harnesses.
The host is deliberately harness-agnostic. local-mac is not
local-mac-opencode; the same host will run OpenCode today, Claude Code
tomorrow, and any future Nexartis harness after that.
Multi-Target Dispatch Vision & Native Engine Stack
Ozzy Dev operates as the on-machine orchestrator. It can spin up and dispatch agent dispatches across three distinct target runtimes from the same local console:
- Local Mac Harness: Ephemeral git worktree containment running local subagents with Thompson Sampling bandit engine selection (
task_class='auto') and diff-content reward signal weighting. - Cloudflare Dynamic Worker Runtime: Serverless edge execution for fast stateless jobs.
- HB3 Cloud Coordinator: High-scale cloud dispatch for multi-agent waves.
Native MCP engines deliver low latency and high reliability:
ozzydev-search(v1.6.0): MoE search router with persistent file-backed hint caching under$WORKSPACE/.ozzydev/hints-cache.json(1ms hint fetch).ozzydev-write(v0.0.10): Rubric-routed write engine with direct-mode priority queue lane (directQueuevsmultiplexQueue) and automatic Prettier post-apply formatting.ozzydev-voice(v0.0.1): Native ElevenLabs TTS voice assistant with CLIspeaksubcommand.
4. Runtime-first discovery
Ozzy Dev discovers agents by asking, in order:
- What runtimes does this machine offer? Host, installed
harnesses, and MCP tool catalog from
mcp/registry.json. - Which agents in KYM support at least one of my host + harness combinations? Query KYM with the runtime filter, then narrow by capability, reputation, and verification type.
- Compile the chosen agent's Cubicle spec for the selected host + harness combination using the matching Cubicle adapter.
- Launch the harness with the compiled plan; stream turns through the ABI Chat SDK; write signed receipts to KYM every turn.
This is the opposite of the "find an agent, hope it works" flow. Runtime capabilities come first; the agent list follows.
5. Harness declaration on the KYM Agent Card
A KYM Agent Card carries the harness declaration under the
x-nexartis-runtime extension:
{
"name": "Ozzy",
"version": "1.0.0",
"description": "Nexartis voice-first on-machine agent for developers.",
"protocolVersions": ["1.0"],
"x-nexartis-runtime": {
"harnesses": ["opencode"],
"supportedHosts": ["local-mac", "local-windows", "local-linux"],
"supportedCubicles": ["ozzy-dev-buyer/v1"],
"model": "anthropic/claude-sonnet-4",
"temperature": 0.2,
"tools": { "*": true },
"permission": { "edit": "ask", "bash": "ask" }
}
}
The runtime-first discovery flow queries this extension. Ozzy Dev
extends the existing assertAgentCardCubicleCompatible helper in the
Cubicle SDK to recognise the local-* hosts.
5. Workspace, Developer & Multi-PR Collaboration Model
Ozzy Dev is designed for multi-workspace, multi-agent collaboration with a zero-friction developer experience:
- Shared Local D1 Database: A single developer machine can host multiple independent workspaces. All workspaces share one local D1 database (
workspaces,repos,workspace_repos,code_maps). This provides instant cross-workspace inventory (GET /api/repos/inventory/cross), tracking which workspace holds which repo, open PR number, branch, and indexed HEAD. - Parallel Waves & Single PR to
dev: In any workspace, parallel agent waves execute across repositories. Per Nexartis conventions, every repository maintains exactly one open PR todev, stacking all concurrent features safely onto that branch. - Rebase Discipline & Content-Aware Freshness: When a PR merges into
dev, parallel workspaces holding checkouts of that repo trigger background content-aware freshness checks (indexed_head..HEAD). Unchanged indexable code automatically re-stamps sidecars without intrusive re-indexing, ensuring search query latency stays under 10ms without impeding the operator. - Zero-Step Bootstrap & Automated Key Distribution: New developers or secondary workspaces run
./bin/bootstrap.sh --use-shared-console. The installer connects to the active console, provisions supervisor LaunchAgents, applies D1 keys automatically, and registers all workspace repositories with zero manual configuration steps.
6. Component architecture
The Cubicle SDK is the security boundary. The ABI Chat SDK is both the session runtime and the UI vocabulary. KYM is the source of truth for agents; NANDA is the discovery + payments layer; Base is the settlement rail. Ozzy Dev is the composition.
7. Install-time flow
The one-time install a developer runs on a fresh laptop.
Status — target vs current. This sequence is the target install-time flow. The current entrypoint is
pnpm run bootstrap(bin/bootstrap.sh): it installs prereqs, builds the vendored SDKs and the native MCP servers, generates the Ed25519 receipt-signer key into the macOS Keychain, applies the D1 migrations, provisions the memory systems viamcp/install.sh, and starts the console. It does not yet request TCC permissions, register a host DID or pull the Ozzy agent card + Cubicle spec from KnowYourModel, compile a Cubicle spec, or gate the console behind a PIN — those steps are planned (host/harness Wave).
8. Per-turn flow
The loop that runs every time the developer speaks or types.
Every completed turn writes a signed receipt back to KYM, which is what makes Ozzy Dev's on-machine execution independently auditable and KYM's reputation graph richer.
9. Agent purchase flow
Discovering, buying, and installing a second agent from KYM through NANDA payments.
10. Component provenance
| Component | Repo / Package | Role in Ozzy Dev |
|---|---|---|
| UI shell + primitives | @nexartis/abi-chat-sdk-svelte |
Shell, chat, command, context, console, form-builder, voice input |
| Session runtime | @nexartis/abi-chat-sdk-core |
Provider routing, SSE bridge, session persistence, tool registry, cubicle bridge |
| Security layer | @nexartis/cubicle-core |
CubicleSpec, validation, opaque refs, host-adapter contract |
| Local runtime adapter | @nexartis/cubicle-adapter-local-mac |
Compiles a CubicleSpec to a local-Mac runtime plan |
| Agent harness | vendor/opencode (Nexartis fork) |
Primary + subagents, plugins, MCP client, tools, permissions |
| Ozzy Dev plugins | plugins/* (this repo) |
KYM loader, Cubicle runner, KYM receipts, voice, discovery |
| MCP catalog | mcp/registry.json (this repo) |
Curated tool inventory installed on the machine |
| Agent registry | KnowYourModel (external service) | Where agents live; receipts flow back |
| KYM SDK | @nexartis/knowyourmodel-sdk |
Typed KYM API + Ed25519 signing |
| Discovery + payments | NANDA Node (external service) | A2A discovery, x402-NP micropayments, USDC settlement |
| Homeport SDK | @nexartis/homeport-sdk |
Typed Homeport (NANDA node) API |
11. Non-goals
- Multi-user session sharing. Ozzy Dev is single-user local.
- Cloud-hosted Ozzy.
local-macis the point; a cloud Ozzy is a different product. - Auto-installing MCP into third-party coding agents (Cursor, Kilo, etc.). Ozzy Dev curates its own catalog for its own harness.
- Off-machine remote driving in the initial waves. Remote Control is a separate, opt-in bridge scheduled for a later wave.
12. Persistence baseline
The console runs on Cloudflare D1. One SvelteKit codebase, one
schema, three D1 databases — one per environment (local, dev, prod).
@sveltejs/adapter-cloudflare binds platform.env.DB in every
runtime; drizzle-orm (drizzle-orm/d1 dialect) is the ORM; migrations
are generated by drizzle-kit and applied via
wrangler d1 migrations apply <db> --remote. vite dev reaches the
real local/shared D1 through wrangler's platform proxy with
remote: true on the binding (adapter-cloudflare platformProxy
option, GA since Wrangler 4.37).
- Databases (schema-identical, forward-only migrations):
local—nexartis-ozzydev-local-console-shared-database(a2353127-a862-4941-93e1-604c98788768, region WNAM). Backsvite devon operator Macs and every local console in the Nexartis org — the "shared vault" per operator identity.dev— workers-dev D1 (690460fe-5cfe-42ad-a2ae-34f78512ef53).prod— workers-prod D1 (400484e4-f299-499d-82a8-2a8da676df44).
- Auth is wrangler OAuth (
wrangler login). That is the entire local credential story — no API tokens on disk, no macOS Keychain master key for the datastore. CI (when needed) usesCLOUDFLARE_API_TOKENscopedAccount → D1 → Edit. - Backups: D1 Time Travel — 30-day point-in-time recovery is the primary durability control. Operator runbook: `RUNBOOKS/d1-time-travel-recovery.md`.
12.a Schema (initial — Phase 1)
Seven tables ship today (v0.4 schema, 0001_machine_scoping
migration); MCP-controller tables land with the D5 controller sprint.
Column-level definitions live in
`SCHEMA-DESIGN-console-d1.md` §3.1.
| Table | Role |
|---|---|
machines |
Per-host row (hostname natural key, auto-registered on first console request). Every workspace + console_state row scopes to a machine. |
workspaces |
Workspace registry — one row per (machine, absolute path); UNIQUE(machine_id, path). Machine-scoped visibility is D1-enforced. |
console_state |
Per-machine singleton (PRIMARY KEY (machine_id)) — carries active_workspace_id for that machine. |
secrets |
Provider API keys — AES-256-GCM envelope in ciphertext, materialised hint, envelope_version (see §12.b, ADR-006 amendment 2). |
applied_secret_targets |
Which workspace files each secret was applied into, for revoke-and-remove flows. |
audit_log |
Append-only trail with request_id, sensitive-field allowlist enforced at write time; secret.rotated is a first-class action. |
settings |
Global / machine / workspace KV — all client-state (UI tabs, filters, per-workspace preferences) lives here; zero localStorage. |
MCP controller tables (mcp_servers, mcp_server_config_history,
mcp_health_probes, mcp_incidents) are deferred to the D5 sprint
(schema doc §3.1.5 amendment A2) — Phase 1 stays on the live-probe
/api/doctor endpoint with no persistence.
KYM still owns agent cards and receipts; the memory systems still own their local indexes under the workspace.
Workspace-tooling home (shipped in WS-A, 2026-07-19). Per
ADR-012 §D-F,
.ozzydev/ at each workspace root is the single home for
workspace-tooling state:
.ozzydev/chunkhound.json + .ozzydev/chunkhound/db (chunkhound
--config), .ozzydev/codesearch/repos.json (via
CODESEARCH_REPOS_CONFIG), the WS-A branch-freshness sidecars at
.ozzydev/{codesearch,chunkhound}/index-meta.json, and (WS-B)
per-workspace daemon state under .ozzydev/daemons/. .serena/
stays at the workspace root (upstream directory-name convention; no
override flag today) and kilo.json stays at the root
(harness-defined). mcp/install.sh runs an idempotent migrate at
every invocation — .chunkhound.json → .ozzydev/chunkhound.json,
.chunkhound/ → .ozzydev/chunkhound/, .codesearch/ →
.ozzydev/codesearch/; if BOTH old and new exist the installer
refuses and asks the operator to resolve (never leave both).
Current-state layout on a bootstrapped workspace is therefore
.ozzydev/{chunkhound,codesearch}/ + .serena/ at the workspace
root. Per-workspace codesearch serve daemons SHIPPED 2026-07-31
(ADR-012 §D-A A1-lazy): mcp/install.sh scaffolds
~/Library/LaunchAgents/com.nexartis.codesearch-serve.<slug>.plist
(slug = kebab workspace basename) on a deterministic port
40000 + sha256(realpath)[0:4] % 2000, with the registry
$WORKSPACE/.ozzydev/codesearch/repos.json baked into the plist env
and the resolved URL written to
$WORKSPACE/.ozzydev/codesearch/serve_url (+ D1
workspaces.metadata.codesearch_url). Serena remains a shared
machine-global streamable-HTTP daemon on :24283 (LaunchAgent
com.nexartis.serena-serve); the machine-global ~/.codesearch/
registry + :39725 codesearch daemon are FROZEN LEGACY for
workspaces bootstrapped from older ozzydev clones — never delete,
never merge into them (see
docs/RUNBOOKS/reset-codesearch-registry.md for the housekeeping
runbook).
12.a2 Multi-workspace, multi-machine model
- One console instance per machine. The console binds to port
5173;
bin/bootstrap.shfails loudly if that port is already in use (vite would otherwise fall forward to 5174 and every probe would silently target the wrong instance). Stop the running console or use it — never run two side-by-side. - Machines auto-register by hostname. On the first request from a
new host, the hook layer upserts a
machinesrow keyed byos.hostname(). No manual "register this machine" ceremony;last_seen_atbumps on every request. Workers runtimes get a stub machine row (demo surface only). - N workspaces per machine. Each workspace is a
(machine_id, path)pair withUNIQUE(machine_id, path). Visibility is D1-enforced: the workspaces list query filters bymachine_id = <this machine>. Two Macs may share the shared local D1 vault and yet each console lists only its own machine's workspaces. - Per-workspace tool configs. Every workspace has its own
kilo.json/.ozzydev/chunkhound.json/.codesearchignore(plus the per-repo tracked.contextignore, the claude-context exclusion file sanctioned by the #372 allowlist our embedded core is patched to), scaffolded bymcp/install.shon install and rewritten (mode 0600) at point-of-use by the secrets apply pipeline. Cursor users mirror the MCP entries viamcp/scaffold/cursor-mcp.json.template→.cursor/mcp.json. - Secrets vault is global, applied-targets are per-workspace. One
secretsrow per integration serves every workspace on every machine the operator signs in on;applied_secret_targetsrecords which workspace files each key has been written into for the revoke/scrub flow. - All client state lives in D1 via the
settingstable. Global / machine / workspace scopes (see schema doc §3.1.6). The UI wave removes everylocalStoragecall in the same PR wave; zero browser-local console state remains.
Local search daemons: per-workspace codesearch (SHIPPED
2026-07-31), shared serena (current). Per
ADR-012 §D-A,
codesearch-serve runs as a per-workspace LaunchAgent
(com.nexartis.codesearch-serve.<slug>) with a deterministic port
40000 + sha256(realpath)[0:4] % 2000, KeepAlive + ThrottleInterval
10 + an ERR-trap that re-bootstraps on mid-script failure; the
resolved URL is recorded in $WORKSPACE/.ozzydev/codesearch/serve_url
and in D1 workspaces.metadata.codesearch_url. The search MCP
resolves the codesearch URL from that field at config load
(search-router ≥ 1.6.0, ADR-007 §2 config_version bump). Serena
remains a shared machine-global streamable-HTTP daemon on :24283
(LaunchAgent com.nexartis.serena-serve); per-workspace Serena is
the next slice under this ADR. The machine-global codesearch daemon
(:39725) is frozen legacy for older-workspace ozzydev clones.
Branch-aware freshness (target — decided 2026-07-19; WS-A defines
the sidecar schema, WS-C mirrors to D1). Every indexer persists
{indexed_head, indexed_at} per repo in shared sidecars at
$WS/.ozzydev/{codesearch,chunkhound}/index-meta.json (schema v1;
see ADR-012 §D-B). Experts compare indexed_head vs
git rev-parse HEAD and fail loud with classified
expert_index_stale; the already-designed
ExpertHit.branch_match and freshness_index_age_s fields are
wired (previously hard-coded null). Auto incremental reindex
runs on workspace activation for the active workspace only;
ChunkHound reindex stays explicit + capped per upstream #365.
Amended 2026-08-01 (ADR-014 D-A): staleness is content-aware — on
a HEAD mismatch with a MATCHING branch the codesearch expert diffs
indexed_head..HEAD and downgrades to fresh when the delta has zero
indexable content, re-stamping the sidecar and marking the receipt
(content_fresh_verified); branch mismatch stays strict.
12.a3 Team fleet model (SHIPPED 2026-08-01, ADR-014 D-B — migration 0006)
Per ADR-012 §D-D as built by ADR-014 D-B, the shared D1 gains:
workspace_repos— per-(workspace_id, repo_id)checkout record (FK torepos, whose natural key isremote_url) withcheckout_path,alias,open_pr_number/branch,indexed_head,indexed_branch,indexed_at, andsemantic_indexed(per-plane flags beyond semantic remain sidecar/doctor-derived today). Upserted byrefresh-index-meta.sh's POST hook after every sidecar refresh;GET /api/repos/inventory/crossreturns every workspace's checkout of one repo side by side — the one-PR-per-repo visibility primitive, verified live with two workspaces on one branch (2026-08-01). The Repos tab D1 read-path and the console/fleetview (machines × workspaces × repos × branches × freshness × last-seen) consume this table next.machine_uuid(IOPlatformUUID) added alongsidehostnameonmachines, so twoTonys-MacBook-Promachines cannot collide.- No
userstable yet. Machine-scoped attribution is adequate until there is a real multi-seat auth story; KYM DIDs are the future identity per the target architecture.
Semantic corpus re-key (target — decided 2026-07-19, ships in
WS-SEM). Per
ADR-012 §D-C,
Zilliz semantic collections re-key from md5(abs-path)[0:8] to
md5(remoteUrl + branch) so team members share the dev-branch
corpus (indexed once by a designated indexer or CI) while per-
workspace ChunkHound covers local deltas. The migration wave is
gated on an override seam around the embedded
Context.semanticSearch path-hashing call — patched in our embedded
@zilliz/claude-context-core or a collection-name override honored
end-to-end (search + insert + doctor probe). Interim: existing
path-keyed orphan detection stays in GET /api/doctor/repos.
12.b Secret storage — envelope encryption (ADR-006 amendment 2)
The vault stores provider API keys as AES-256-GCM envelopes in
secrets.ciphertext (v1.<iv>.<ciphertext>.<tag> base64), alongside
a materialised hint (masked preview, computed at write time) and an
envelope_version gate for future format migrations. The 32-byte
machine master key lives in the macOS Keychain on the operator's
Mac (service com.nexartis.ozzydev, account secrets-master-key,
created on first use). The DB never sees key material; the Keychain
never sees secret values.
Per the 2026-07-12 operator directive ("all data lifecycle in D1 AND api keys encrypted per best practice with rotation"), this supersedes the same-day plaintext-at-row-level amendment. See `DECISIONS/ADR-006-encrypted-secrets-vault.md` → Amendment 2 — 2026-07-12 · Envelope encryption reinstated.
Runtime split:
localruntime holds the master key and is the only runtime that decrypts. File-apply of the plaintext to.ozzydev/chunkhound.json/kilo.jsonis local-runtime-only.workers-dev/workers-prodruntimes can list vault metadata (id, integrationId, hint, timestamps, applied targets) via the write-only contract but throwrequires_local_runtimeon any decrypt or apply — loud, never silent.MasterKeyErrorcontract retained. Keychain lookup failure surfaces asmaster_key_unreachable(HTTP 500). No silent regeneration, no fresh-start fallback that would invalidate stored ciphertext.- Rotation = re-save. Verify-live-on-save → encrypt under the
current master → upsert → re-apply to every
applied_secret_targetsrow. Audited assecret.rotated.
The compensating-controls stack from amendment 1 REMAINS as defense layers beneath envelope encryption (they no longer stand alone):
- D1 at-rest encryption — Cloudflare-managed keys cover the storage tier under the envelope.
- Wrangler OAuth-scoped access — the only human path into a row
is
wrangler d1 execute/ D1 dashboard, gated on the Cloudflare account and access-logged. - Audit-log fixed-key allowlist —
audit()refuses to write plaintext or ciphertext intoaudit_log.detail;secret.rotatedjoins the allowlist; unknown keys fail loud withaudit_unknown_field. - Verify-live-on-save — provider-verify gates acceptance before encryption. Possession of a rotated ciphertext without a live verify does not re-apply anywhere.
- Apply-time 0600 files — applied configuration files
(
.ozzydev/chunkhound.jsonembedding block,kilo.jsoncontext7 header- morph env) are machine-local, mode 0600, untracked.
12.c Non-negotiables (workspace §2 alignment)
- No silent fallback between D1 and local SQLite. If the binding
is unavailable (offline, not logged in), the console fails loudly
with a classified
datastore_unreachableerror and a fix-it hint (wrangler login/pnpm run deploy:local).bin/bootstrap.shprobes/api/secretsafter readiness and hard-fails on 503 rather than continuing into secret re-apply against a broken binding. One datastore, one code path. - Loud failure surfaces in the UI — a dedicated "datastore unreachable" state on every data-backed page.
- Forward-only migrations — every schema change is a generated,
committed migration; no
drizzle-kit pushagainst the shared DB. Time Travel is for data recovery, not schema rollback. request_idon every mutation.hooks.server.tsassigns a ULID, threads it into everyaudit_logrow and every classified error envelope, so a support session traces a UI action to its DB effects and its log lines.- Machine-scoped workspace visibility (D1-enforced). The
workspaces list query filters by
machine_id; a workspace row from another machine on the shared D1 is invisible to this console. Applied targets follow the workspace scope; secrets are global per operator identity.
12.d Migration story (fresh start)
Legacy local vault data (~/.ozzydev/console.db,
~/.ozzydev/workspaces.json, and any prior secret-crypto.ts
envelope contents in those files) are abandoned in W2 — no
automatic migration, no pre-seeding from any legacy file (silent
behavior we explicitly avoid, workspace §2). The node:sqlite
adapter is the only piece actually retired: production storage moved
to Cloudflare D1. secret-crypto.ts and the macOS Keychain master
key entry (com.nexartis.ozzydev / secrets-master-key) are
current, not abandoned — ADR-006 Amendment 2 reinstated envelope
encryption at the row level (AES-256-GCM v1.<iv>.<ct>.<tag> stored
in secrets.ciphertext, master key held only on the local
runtime). Operators re-enter each key once through /system → API Keys; verify-live-on-save is the acceptance contract, and
applied_secret_targets rows are rebuilt as operators re-apply.
One-time cost, permanent win.
12.e Endstate file map
console/
wrangler.jsonc # DB binding → shared/dev/prod D1, remote: true
drizzle.config.ts # dialect sqlite, driver d1-http (for generate only)
migrations/ # drizzle-kit output, applied via wrangler
src/lib/server/db/ # drizzle client factory + schema (source of truth)
src/lib/server/secrets.ts # typed drizzle queries; no crypto
src/lib/server/runtime.ts # capability module — local vs workers-dev/prod
src/lib/server/errors.ts # ConsoleError + handleError (request-id envelopes)
12.f Native MCP servers (search + write + harness + voice)
Four first-party MCP servers ship under mcp/servers/ and are seeded
into mcp/registry.json alongside the third-party catalog:
mcp/servers/ozzydev-native-search-mcp— the MoE search router (ADR-007, the fifth memory system alongsidechunkhound/codesearch/serena/context7; the chunkhound MCP is re-enabled read-only per D4, while the router semantic slot is claude-context + Zilliz Cloud pending the bakeoff, with our embedded core carrying the #372 ignore-allowlist patch, ADR-007 §2.1). Per-repo coverage of the memory systems — codesearch/group/serena/semantic + ignore hazards- orphaned-collection detection — is live at the console
/memoryRepos tab (GET /api/doctor/repos). Classifies a query into an intent class, fans out to per-class experts, and fuses via RRF. Shipsenabled: truein the workspacekilo.json. Baseline metrics and the soak / chaos / adversarial harness live in `DECISIONS/BENCHMARK-PLAN-ozzydev-native-search-mcp.md`.
- orphaned-collection detection — is live at the console
mcp/servers/ozzydev-native-write-mcp— the rubric-routed write + verify server (ADR-008). Routes each edit to the right write tool (native / morph / relace / weave / ast-grep / serena) by the AGENTS.md §1 write rubric, then verifies the on-disk result.enabled: truesince 2026-07-16 (wave-1-4 milestone): the r2–r5 bakeoff program completed the pre-enable gate — a deterministic splice-first preflight resolves ~74% of real lazy edits at $0/0ms and hands classified failures to the vendor arm (fast_apply_engine = morph, chosen on reconciled artifact evidence; Relace stays as the one-flip alternate). On a fresh workspace the entry scaffoldsenabled: false; saving a verified Morph key in the Secrets panel fansMORPH_API_KEYinto theozzydev-writeenv and flips it on (applyMorph, 2026-07-16 — splice preflight itself is keyless).mcp/servers/ozzydev-native-harness-mcp— the harness engine router (ADR-013). Routes a unit of work to a harness EngineAdapter (generic seam — vendors like acp/cli engines are config, never type identifiers), runs the verify ladder, and emits a receipt. Scaffoldsenabled: false(bench-harness driven).mcp/servers/ozzydev-native-voice-mcp— native voice / TTSspeak_update, extracted fromnexartis-remote-controland dependency-free: a bundled Python-stdlib ElevenLabs runtime (voice-runtime/) + a node-builtins spawn wrapper + a@modelcontextprotocol/sdkstdio server. No console/receipt coupling (voice is an output modality, not a code-write); key viaELEVENLABS_API_KEY; scaffoldsenabled: falseuntil the key is provisioned. Registry catalog categoryvoice.
The receipt-coupled servers (search / write / harness) emit
ADR-009 Ed25519-signed receipts for every
tool call into the console D1 (tool_benchmark_events +
experiments tables), so their behavior is independently auditable
on the same rail as KYM turn receipts (§8).
12.1 Runtime targeting & environment model (D1 refactor)
The D1 refactor lands with an explicit three-environment runtime
model. The console is one SvelteKit codebase deployed against three
runtime targets; environment is declared, never sniffed. Selection is
via the OZZYDEV_RUNTIME variable set per wrangler env (local,
dev, prod).
local— primary sidecar runtime.vite devon the operator's Mac. Fullnode:fs,node:child_process, and shell access are available;platform.env.DBis provided by wrangler's platform proxy withremote:trueagainst the local/shared D1 (a2353127-a862-4941-93e1-604c98788768). This is the primary runtime — Ozzy Dev is the on-machine agentic client (§3), and every local-only capability (file-apply of secrets, subprocess health probes, MCP supervisor introspection) targets this runtime.dev— workers-dev.wrangler deploy --env devtargets the dev D1 (690460fe-5cfe-42ad-a2ae-34f78512ef53) and is used for demos and the future cube-plugin surface.node:fsis a per-request ephemeral sandbox;node:child_processis a stub. Local-only features fail loud with a classifiedrequires_local_runtimeerror — never silently degrade.prod— workers-prod.wrangler deploy --env prodtargets the prod D1 (400484e4-f299-499d-82a8-2a8da676df44). Same sandboxing and samerequires_local_runtimecontract as dev.
Three D1 databases, one per environment, identical schema
(schema doc §5 Q2). Deploy convention: deploy:local runs the local
start command; deploy:dev and deploy:prod run the matching
wrangler deploy --env invocations. The workers deploys are for
demos and the future cube-plugin surface today; they are not the
Ozzy Dev product.
The canonical runtime contract lives in the Cubicle SDK — see
`_NEXARTIS-SDKs/nexartis-cubicle-sdk/docs/sdk-architecture.md`.
The relevant machinery: the HB3 container adapter vs the
cloudflare-dynamic-worker adapter, and the
x-nexartis-runtime.supportedCubicles field on the KYM Agent Card
that declares which runtime an agent supports. This document does
not duplicate those definitions; it cross-references them.
Product direction. Ozzy Dev's local runtime is the harness we use to determine the default Cubicle tool loadout and the runtime-capability categorization of every agent and skill. Preferred loadout is the cloudflare-dynamic-worker adapter (fast cold starts, cheap, no supervisor); containers via the HB3 adapter are reserved for agents that genuinely require them. The HB3 Cloudflare container runtime itself ships after MVP — local Mac + dynamic-workers is the MVP surface.
Cloud exposure + domains. Per fleet convention (mirroring
helix-command-center/wrangler.jsonc), each workers env carries a
custom domain: dev.ozzydev.com (dev) and
ozzydev.com (prod); the corresponding
nexartis-ozzydev-console-{dev,prod}.workers.dev names remain as
Cloudflare-managed fallbacks. Both workers runtimes are gated by
@nexartis/sentinel-sdk
(fleet pattern): hooks.server.ts runs the Sentinel handle, then a
Sentinel admin authorization wrap. Public on workers: GET /
(landing), the entire /auth surface (login, magic-link processing,
verify/verified, magic-success, unauthorized), the /api/auth/*
catch-all handler, and framework/static assets. Registration is not
self-serve on this console — every mutating request to
/api/auth/register is short-circuited with a loud classified 403 forbidden before Sentinel's handler runs, since accounts are
provisioned inside the Sentinel system directly. Every
other page and every other /api/* requires locals.user.roles
containing admin — unauthenticated pages 302 to
/auth?redirect=…, unauthenticated APIs return the classified
admin_auth_required (401), authenticated non-admin pages 302 to
/auth/unauthorized, and authenticated non-admin APIs return
forbidden (403). The local runtime is completely unaffected —
it is the machine trust boundary, and agent tooling
(telemetry-emit, doctor, memory admin) depends on ungated
127.0.0.1:5173.
13. Related documents
- Roadmap — waves, exit criteria, current sprint, tech-debt log —
lives in the console at
/roadmap(console/src/routes/roadmap/+page.svelte). - Research — long-lived technical white papers, in the console at
/research. - `OPENCODE_VENDORING.md` — how the vendored fork is kept in sync.
- `DECISIONS/` — architectural decision records.
- `../AGENTS.md` — repo-specific agent behavior and the Nexartis release convention.