futura-scion
v0.10.0
Published
The fused scion of cortex-os-agent + persona: one zero-LLM-dependent agent stack — Mind proposes, Muscle executes, Gate disposes.
Maintainers
Readme
futura-scion
The scion of two proven parents: cortex-os-agent (a knowledge Mind) × persona (an execution Muscle), grafted onto a single evidence Gate. One agent stack, zero LLM dependency, maximum capability. v0.10.0: A BOUNDED CONTEXT + A GATE THAT NOTICES ABSENCE — the freebuff study (research/freebuff_lessons.md) rebuilt for a zero-LLM harness.
scion compact <taskId>bounds a task's context MECHANICALLY (no model call): the request verbatim, outcomes never summarised — it refuses rather than drop an exit code — references headed, notes outlined, omissions NAMED, and a rewrite that does not shrink is a journaled no-op.npm run verifyadds the suite gate: test/file counts judged against a committed baseline, a drop refused with its delta named, an unparsed total treated as unknown (never a pass), and--updaterefusing a non-green run. Applying "a gate must notice absence" to FS's own event map then found a hole in it: both scanners matched a case-sensitivejournal(, hiding 43 kinds that were journaled in production — the catalog is now 345 kinds, the ternary call sites are literals, and the gate refuses a kind chosen by an expression. v0.9.0: SPEC-DRIVEN PIPELINE + PLUGINS + A READABLE JOURNAL —scion specturns a feature name into the three reviewable artifacts (requirements → design → tasks) andcompileputs the open tasks on the queue, where the Gate judges them like any other work;scion pluginsinstalls, lists and loads declared plugins (a directory withscion-plugin.jsonand aregister(scion)export) with the earn ledger as the ranking.scion help(and-h/--help) now renders the WHOLE command surface from one registry, machine- checked against the dispatcher so help cannot drift again; and the HTTP, daemon and swarm surfaces finally stamp their own rows — a serve process journalshttp, notcli, sotrail.bySurface()tells the truth. The journal is finally readable from OUTSIDE the UI:scion eventsspeaks one versioned envelope (NDJSON for scripts,--followfor a live tail,--infofor the contract, and a LOUD exit 2 naming near misses for an uncatalogued kind) over the same/ui/events+/ui/events/streamroutes, andscion auditanswers what the harness refused, what failed and why — filterable,--csv-exportable, with a cap that states what it hides. Andscion compact <taskId>bounds a task's context MECHANICALLY (no model call): the request verbatim, outcomes never summarised — it refuses rather than drop an exit code — references headed, notes outlined, omissions NAMED, and a rewrite that does not shrink is a journaled no-op. v0.8.0: PORTABLE MODELS BY ID — a wheel is declared by its Hugging Face id (repo+hf_file) instead of a copied URL, so the SAME model lands on any machine:scion acquire hf <org/name[@file.gguf]>, a Settings → "Download from Hugging Face" field in the UI, and the shipped defaults carry this box's 9B coding wheel and 4B fast wheel by id. The packaged desktop shell now runs the kernel from a writable home, so an installer on a fresh machine completes itself. v0.7.0: COMPLETE ON DEMAND — the npm tarball ships no llama-server (platform-specific), soscion acquire [status|fix|server|model <id>]reconstructs the stack (exit 1 = gaps, script-gateable),llm.server.acquire.auto: truefills gaps at first required use, andscion doctorgrew anllmprobe that names the exact fix. v0.6.0: the ON-THE-FLY ROUTER — declared problem→wheel rules pick the right model per call (mix-and-match candidates ranked by measured route earn → declared speed → declared order), outcomes fold back into a route earn ledger, vision rides along as a wheel-scoped projector, plusscion config dump(the effective config, secrets masked), closed-union step dispatch (assertNever), and the shipped event taxonomy map (docs/EVENTS.md). v0.5.1: zero-LLM parity — the solver cascade (four deterministic rescue strategies before escalation), cited extractive research answers, and learned-playbook tool selection (docs/PARITY.md); nested file paths parse as one slot. v0.5.0: operator sovereignty — the plan-approval gate (FS proposes, you dispose), lifecycle hooks, the checkpoint timeline, the PR review bot, and a pluggable docker executor; every knowledge surface measures what earns its keep, and the ledgers now have a TIME dimension (trends + learned playbooks). Earlier: v0.4.0 ran the daily learn→build→improve→repeat cycle unattended with both earn ledgers; v0.3.0 carried the broker, autonomy clock (cron/goals/notify), racing Mind, and FS Desktop; v0.2.0 grafted in the agentic-cortex brain (one SQLite database, restart-surviving, temporal memory, semantic recall).
Install — one command, and models are optional
npm install -g futura-scion # or: npm install -g . from a checkout
scion setup # what works here, what is optional, what finishes it
scion run "describe a problem" # works right now — no model, nothing downloadedscion setup separates two verdicts so the distinction cannot blur:
operable (the deterministic ladder works on this machine — the gate, and
independent of every optional component) and accelerated (the optional
local model stack is present — nice, never required). scion setup
--acquire downloads that stack when you ask; nothing downloads otherwise.
Four operating profiles, all fully usable, none of which remove a capability:
| profile | what is armed | CLI |
|---|---|---|
| offline (shipped) | nothing — deterministic ladder only | scion components mode offline |
| assisted | a local wheel, inside a daily token budget | scion components mode assisted --tokens N |
| free | a local wheel, uncapped (spend still journaled) | scion components mode free |
| remote | an external OpenAI-compatible endpoint | scion components mode remote --provider … --base-url … --model … |
scion components prints what this deployment is made of — every component,
its state, its off-switch, and the exact command that fixes a gap. A profile
whose engine is missing is refused with the fix, never silently half-armed.
The FS Desktop Settings → Operating profile panel drives the same
validated paths (mode buttons, per-component enables, plan/dry-run/install).
Full walkthrough: docs/INSTALL.md.
What it is
┌─────────────────────────────────────────────────────────────┐
│ scion CLI / daemon / swarm (interactive · guided · auto)│
├─────────────────────────────────────────────────────────────┤
│ MIND seeds · corpus · reasoner · replay · curator model │
├─────────────────────────────────────────────────────────────┤
│ MUSCLE queue · leases · bounds · policy gate · swarms │
│ racing · quorum · A2A-ready transport │
├─────────────────────────────────────────────────────────────┤
│ GATE verify→revert · held-out validation · certificates │
└─────────────────────────────────────────────────────────────┘The Mind proposes, the Muscle executes, the Gate disposes.
Install (works on any machine)
Requires Node ≥ 20. From the repo (or after npm publish, from the registry):
# install globally from a packed tarball or the repo itself
git clone https://github.com/zallauddin/FuturaScion.git && cd FuturaScion && npm install -g .
# or
npm pack && npm install -g futura-scion-<version>.tgz
# or, once published:
npm install -g futura-scionThat puts three commands on PATH:
scion— the agent:scion run "fix var in src/x.js",scion analyze .,scion tools research "why is the build flaky",scion watch,scion swarm 4,scion(REPL)scion-mcp— the MCP stdio server (wire into Claude Desktop, IDEs, other agents)scion-cert— offline verification of evidence certificates
Verify the install against any project:
cd your-project
scion analyze . # scan the tree
scion run "fix var in src/legacy.js" --intent fix # fix + gate-verify + certificate
scion brain --all # fleet-brain memory inventoryComplete on demand (v0.7.0) — acquire from the CLI, the UI, or a boot
A fresh npm install futura-scion ships no llama-server binary and no
model — binaries are platform-specific, so every tarball would carry the
wrong OS's build. Instead FS reconstructs the stack when it's required,
through three surfaces on one journaled channel (llm.server.acquired /
llm.model.acquired, .part → rename, interrupted reads interrupted —
never a phantom success):
- CLI —
scion acquireprints the availability matrix and exits 1 while incomplete (scripts gate on it; not an error).scion acquire fixfills every gap it can: server archive →install_dir, served GGUF → its catalog download.server/model <id>fetch one piece, andhf <org/name[@file.gguf]>fetches any GGUF by Hugging Face id (catalog or not — see the portable section below). Gaps with no URL (local wheels,mmprojprojectors) come back named with the exact fix — never silent, never a partial install. - UI — the Settings → Download buttons drive the same functions
(
POST /ui/llm-server/acquire) with live progress. - Automatic (opt-in) —
llm.server.acquire.auto: true: a boot that finds a missing server or served GGUF reconstructs it first, then boots; if a gap remains it fails loud naming it. Defaultfalsekeeps the zero-LLM posture — an installed FS stays inert until asked. scion doctorgrew anllmprobe — unarmed (daily_tokens: 0) passes clean; armed-but-incomplete is a warn whose detail is the fix (scion acquire fix). It degrades, never blocks the zero-LLM loop.- Honest plumbing — the archive filename follows the URL (
.tar.gzactually reachestaron POSIX; before, everything was named.zip), both residue names are cleaned, andmodelIdForPath()maps a served GGUF back to its catalog id so errors sayscion acquire model qwen3-4b, not just "missing".
Portable models by ID (v0.8.0) — the wheel follows you
This box runs two wheels: a 9B coding wheel (Qwythos-9B Claude Mythos,
~5.9 G, 1 M ctx, vision) and a 4B fast wheel (Qwen3.8-4B, ~2.8 G).
Neither is named by a path or a copied URL. Each carries its Hugging Face
id in config — repo + the exact hf_file — which is the whole
interface, and that is what makes the stack reproduce elsewhere:
llm:
server:
acquire:
models:
qwythos-9b:
file: ../Qwythos-9B-Claude-Mythos-5-1M-GGUF/Qwythos-9B-Claude-Mythos-5-1M-MTP-Q4_K_M.gguf
repo: empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF # portable: the same wheel anywhere
hf_file: Qwythos-9B-Claude-Mythos-5-1M-MTP-Q4_K_M.gguf
mmproj: mmproj-Qwythos-9B-Claude-Mythos-5-1M-f16.gguf # vision rides alongThree ways to use it, all on one journaled channel:
scion acquire hf empero-ai/Qwythos-9B-Claude-Mythos-5-1M-GGUF
scion acquire hf empero-ai/[email protected]_K_M.gguf
scion acquire model qwythos-9b # the catalog entry, resolved by its repo idscion acquire hf <id>— any GGUF, with or without a catalog entry.@file.ggufpins the filename; the id alone picksQ4_K_Mfirst (the proven pairing default) and never mistakes a projector (mmproj*) or a split shard (-00001-of-00004) for the weight. The repo's own file list is asked for, so a renamed quant or a new repo needs no code change — and an id whose wheel has eyes reports the projector's exact name (fetch it with the same form:[email protected]), because a vision wheel is not "ready" without it.- UI — Settings → Download from Hugging Face takes the same id;
the catalog rows show each wheel's
HFid so it can be read off and reproduced on another machine, and the transfer shows live progress (by-id jobs are reported on their own line — no fake catalog row). - Failures are named, never guessed — a bare name (no
org/) is refused before any network call, a 404 says the id is wrong, a 401/403 saysHF_TOKEN(private/gated repos read it from the environment, never from config and never journaled), and an unknown@filelists what the repo actually holds. - The desktop shell is portable too — a packaged FS Desktop spawns the
kernel from the writable app home (not read-only
app.asar), so a fresh install on another machine is: install Node →npm i -g futura-scion→ Install server → fetch a wheel by id. Works the same fromscion ui.
Spec-driven pipeline + plugins (v0.9.0) — the big-feature front door
Two capabilities the market made table stakes (Kiro / GitHub Spec-Kit for specs, Claude Code / Goose for plugins) are now FS organs — deterministic, zero-LLM, journaled.
scion spec — requirements → design → tasks, reviewable before code
scion spec new checkout-hardening --title "Checkout hardening"
scion spec list
scion spec show checkout-hardening
scion spec compile checkout-hardening --enqueue # open tasks become REAL queue tasksnew writes specs/<name>/{requirements,design,tasks}.md from deterministic
templates; it refuses to overwrite an existing spec (adjacent, never
rewrite — --force is explicit). compile strips HTML comments (so template
examples are documentation, never fake tasks), feeds requirements.md through
the brief organ — every MUST/SHOULD line is classified checkable-or-judgment —
and enqueues each OPEN - [ ] task as an ordinary task with its verify:
command carried as the evidence contract. A [x] task enqueues nothing. The
Gate disposes: a spec task passes or fails like any other.
Task lines are - [ ] T1: text (verify: cmd); an id-less line takes the next
number, and an id with no text is a loud authoring error naming its line — an
empty task is a silent no-op, so it is refused instead.
scion plugins — distribution, with measurement as the ranking
A plugin is a directory with a manifest and an ESM entry:
{ "name": "acme-tools", "version": "1.0.0", "entry": "index.js",
"description": "what it adds" }export function register(scion) {
scion.journal('acme.ready', { version: scion.version });
return [() => { /* disposer */ }];
}scion plugins add ./acme-tools # validated, copied, journaled (refuses a second install)
scion plugins list
scion plugins run # load every plugin's register(scion) into this process
scion plugins remove acme-toolsserve loads plugins at boot (fail-safe: one broken plugin is journaled and
skipped, the server still starts; plugins.enabled: false is a declared
no-op). The facade is assembled by the surface, never by the kernel — a
plugin receives exactly what the deployment hands it. An install is validated
BEFORE anything is copied (name, semver, and an entry that may not escape
its directory), so a bad manifest never leaves a half-installed plugin behind.
Because a plugin's tools enter the measured earn ledger on first call, ranking
is evidence, not votes.
scion help — the whole surface, drift-proof
scion help # every command, grouped; exits 0
scion help spec # one command's usage line
scion -h # aliasThe surface used to be a hand-written string that had drifted ~30 commands
behind the dispatcher, and --help printed unknown command: --help. The
registry now lives in one module and test/cli-manifest.test.js asserts the
registry and the dispatcher's case labels are the same set in both
directions — a command without a help line, or a help line with no command,
fails the build.
Provenance, actually fixed
src/http.js, src/daemon.js and src/swarm.js declared their surface at
module load, but bin/scion.js sets cli after every hoisted import has
already run — so the module-level stamp was dead and a serve process could
never journal an http row (api.started came out as cli). The declaration
now happens at runtime, in the entry-point case that is actually running
(serve → http, watch → daemon, swarm → swarm), and a test spawns a
real server and asserts the row's origin — the parity rule's "which path
produced this row" is queryable again.
The on-the-fly router (v0.6.0) — mix, match, and the route earn ledger
The LLM rungs used to have exactly one model. Now the problem picks the
model, every call, from rules you declare (llm.routes in
config/scion.config.yaml) — and the ledger remembers which pick paid off:
- Declare routes, not swaps — a route matches on
kinds(prefix/star),text_any(substring), orfile_glob(full path or basename,**/spans directories); first declared match wins.serve:targets a local wheel (catalog id or GGUF path — swapped in, persisted, journaled),baseUrl+modeldials another endpoint as-is. No match = the default config, zero journals, zero swaps. Malformed rules fail loud at load with the offending path (llm.routes[i].field); an unresolvable target journalsllm.route-errorand throws — never a silent wrong-wheel fallback. - Mix & match (
candidates:) — one route, several possible targets; the chooser ranks them per call: available (a wheel that isn't on disk is named and skipped; all-down is loud) → measured route-earn (the Gate is the only credit — proven zero-yield targets are skipped while an alternative survives) → declaredspeed_tps(unknown = last) → declared order. Every pick journals its inputs: target, earn, tps, ranked list, skips. - The route earn ledger — dispatches (
llm.route) join to folded worker outcomes (llm.route-outcome, solved/failed per task) into an earn rate per target. Unproven targets staynull— never invented. As injected training data changes what a wheel can do, its measured earn moves and the chooser follows — best result at all times, evidence-earned. - Vision rides the wheel — a catalog entry may declare
mmproj; the projector boots with--mmprojonly while its wheel serves (a swap to another wheel boots without it), and a declared-but-missing projector fails loud with the path. Live: image →"Red", text →"144". - Wheels on the models drive — catalog entries with no URL never
download:
fileresolves relative to the served model's directory (the../<folder>/form works from either sibling wheel),speed_tpsis the declared decode speed the chooser tiebreaks on, and the serving flag compares resolved paths — a hand-written..is still the same file. - The seam — routing lives inside the generator every rung constructs,
so CLI, daemon, and swarm route identically (the parity rule); gauge arms
pass
{ routes: false }so an A/B always measures the spec it was given. - Also new —
scion config dump(the booted process's effective config, defaults merged, secrets masked/pattern-redacted — paste-safe),scion doctor --strictactually reaches the gate (the documented flag was parsed from the wrong argv slot), native workflow steps dispatch through a closed union (src/exhaust.js— an unknown type throws instead of pretending read-only), and the event taxonomy is shipped as data:docs/EVENTS.md(252 trail/channel kinds, test-pinned byscripts/gen-events-map.mjs) with the capability contracts indocs/SEAMS.md.
Zero-LLM parity (v0.5.1) — the rescue pass, cited answers, the head-to-head
The full case against LLM-backed agents is docs/PARITY.md — 15
capability rows, each naming the LLM-agent behavior, the FS organ, and its
evidence site, plus the economics (evidence compounds; prompts don't). What
landed in the product:
- Solver cascade — when the R2 research rung comes back thin, FS exhausts
deterministic strategy space before escalating: re-read (the problem
re-keyed with its own key terms), re-search (query-planner variants),
analogous (the nearest verified replay neighbor), decompose (split into
facets, research each). First verified hit wins, every attempt journals
solver.cascade, each strategy runs under a hard wall clock (cascade.per_strategy_ms), and the cascade never retries a network that already returned zero pages — bounded > exhaustive. - Cited answers —
scion research "…"now ends with an extractive answer: claims QUOTED from corroborated sources, a bibliography ranked by citation count, honest confidence, and named open questions (conflicts, failed gate checks). The decision trail carriesanswer+cascadeon the research candidate. - Learned playbooks drive tool selection — mined playbooks feed the
research chain when built-in keywords miss (
min_supportdeclared), so the earn ledger picks the tools that actually paid. - Deep honesty in the NLU — nested paths (
fix demo/fixture/app.js) now match as ONE slot; a split path used to validate the directory half and send the analyzer a folder. (Found by driving the demo, not by CI.) - Benches moved out of test discovery —
test/bench/→bench/; the suite was running a full worker+Gate benchmark as a "test". 464/464 in ~5 minutes again. demo/— a self-contained walkthrough page, verbatim captures of every session, and three recorded videos of the UI (seedemo/README.md).
Operator sovereignty (v0.5.0) — the human gate, hooks, and undo
FS is built to run unattended, but unattended ≠ unsupervised. Three organs put the operator in command:
- Plan-approval gate — set
bounds.approval: requiredand every mutating task freezes in statusplanned: claim-proof, invisible to workers, until you runscion approve <id>(orPOST /tasks/<id>/approve).scion planslists what awaits;scion reject <id>takes the escalation lane as a verdict.journal-onlymode records every plan on the hash-chained trail without gating. The FS Desktop Plans panel (Review view) approves and rejects with a click. - Lifecycle hooks — declared shell commands fired at the moments that
matter:
onGatePass(deploy a canary),onGateFail,onTaskFail,onEscalation,onPlanApproved/Rejected. Journaled (hook.*), blocklist-guarded, wall-clocked, and honest: hooks receiveSCION_HOOK_TASKandSCION_HOOK_EVIDENCE(rung, cert digest, files touched, gate exit codes) so a deploy hook gates on what was verified. - Checkpoint timeline — before the applier touches a file, runTask
snapshots it under
.scion/checkpoints/<task>/<seq>/with sha256 digests.scion checkpoints list <task>+restore <task> <seq>give byte-exact undo (FS Desktop has a Checkpoints view). Retention is declared:bounds.checkpoint_keep_last(default 20, 0 = unbounded).
Also new in v0.5.0:
- PR review bot (
scion review pr --patch <file>,POST /review/pr) — an inbound unified diff is reconstructed with context verification (a stale hunk is reported, never faked) and run through the project's REAL Gate per file; the verdict carries per-file exit codes and a reproduce list. - Pluggable executor —
bounds.executor: docker(+executor_image) runs every verifier command in a one-shot container with the workspace bind-mounted;process(default) is unchanged. Misconfiguration fails loud. - Worktree isolation, hot-wired —
muscle.worktrees: truemakes tasks targeting files OUTSIDE the scion checkout execute in an isolated git worktree under the target repo; only gate-verified work merges back. - Earn ledgers grow a time dimension —
scion tools trend [days](day-bucketed earn rates),scion tools pools(cross-registry: is this tool a specialist or a generalist?), andscion tools playbooks(tool chains LEARNED from the trail — observed consecutive pairs with support and earn rate, extending the built-in CHAIN_PLAYBOOKS). - Memory CRUD —
scion memory ls|get|forget [--hard]and/ui/memoryroutes: the brain's knowledge is operator-reachable, soft-delete journaled. - A2A capability routing — remote workers declare competences and claim
through the SAME role predicate as local swarms;
scion swarmtakes real tasks (free-text args or--manifestJSON) instead of a demo loop.
The brief organ — context in, verified contract out
FS's rungs act on commands, but real work arrives as CONTEXT — tickets,
specs, conversations. The brief organ (scion brief, docs/brief.md)
ingests a context document and produces a structured problem model:
entities, business rules (MUST/never sentences), acceptance criteria
(Gherkin Given/When/Then, bullets). Each requirement is classified
checkable (compiles to a Gate verifier command — the same oracle that
judges code judges the business rules) or judgment (kept visible for
the clarify/review loop, never dropped). A failing requirement vetoes
completeness, so FS cannot declare work done while the contract is
broken.
Temporal memory: forgetting, supersession, semantic recall (cortex lineage)
The brain never grows stale or noisy — two deterministic organs (ported from agentic-cortex, LLM-free throughout) keep it sharp:
- Temporal expiry — a memory whose text carries a deadline (
2026-12-25,in 3 days,tomorrow, or an explicitttlDays) gets that lifespan on save;scion brain --sweepsoft-deletes everything whose time has passed. - Supersession — saving a statement-like fact with a near-identical title
(
deploy is Mondayoverdeploy is Friday) marks the old factsuperseded_bythe new one and excludes it from retrieval. Gate-verified memories are append-only evidence and never auto-supersede. - Semantic recall — every memory carries a deterministic 512-dim
hashed-feature vector (no model, no download, byte-identical on every
machine). Hybrid search blends FTS keyword rank with vector similarity;
when FTS cannot match at all (morphological near-misses like
pools exhaustingvspool exhaustion), retrieval falls back to vector-only.scion brainreports the forgetting ledger (superseded/expired).
FS Desktop (the UI)
The web UI ships inside the npm package — one command after install:
scion ui # boots the kernel + opens FS Desktop in the browser
# or: scion serve, then open http://127.0.0.1:5107/uiWindows installer (two-tier)
A native Windows app is also built from this repo:
cd desktop && npm install && npm run dist # → dist-desktop/FS-Desktop-Setup-<ver>.exeThe shell is a thin Electron host (~78 MB installer) that detects the npm kernel at
launch: if futura-scion is installed globally (or SCION_BIN is set) it spawns
scion serve itself and opens the UI window; otherwise it shows a guided setup screen
with the one-line install command and a Retry button. The kernel always runs under the
user's own Node — updates flow through npm update -g futura-scion without
re-installing the shell. Silent install: FS-Desktop-Setup-<ver>.exe /S.
The packaged shell runs the kernel from its writable app home (app.isPackaged
→ userData; SCION_CWD overrides), because a kernel pointed inside read-only
app.asar could never download a model. So a fresh install elsewhere needs no
hand-placed paths: it boots on the shipped defaults and completes itself from
Settings — Install server, then a wheel fetched by Hugging Face id.
better-sqlite3 ships prebuilt binaries for common platforms (Linux/macOS/Windows,
x64/arm64); exotic platforms need build tools. FS keeps its brain per project
(.scion/), reads config from config/scion.config.yaml (or shipped defaults),
and never phones home — no LLM, no network, no telemetry.
The unified trust ladder (every rank above the LLM costs zero tokens):
1. replay — verified verdict from the learned index (0 LLM, 0 tokens)
2. seeds — detection/fix patterns forged from verified history
3. analyze — deterministic detection over real source: transformable
findings become exact-string patch candidates
4. memory — brain recall: FTS5 search + always-injected principles
5. reasoner — 6-mode deterministic inference over the knowledge graph
(deduction · induction · analogy · abduction · synthesis · forecast)
6. web — signature-keyed corpus, scored by verifier pass-rate
7. (llm) — OPTIONAL, off by default, budgeted; candidate only
8. escalate — human / decisions queueEvery candidate — from any rung — crosses the same Gate before it is real.
One-shot self-repair (scion plan <target> --run)
scion plan turns analyzer findings into a fix workflow automatically:
transformable findings become fix tasks, sorted by file then line, and
patches to the SAME file are chained with depends_on edges so line numbers
stay valid as earlier patches rewrite the file. Cross-file patches stay
independent — no artificial edges. Flag-only findings (no deterministic
transform) are excluded: they need a human, not a patch.
scion plan src/ # print the manifest (inspect the DAG first)
scion plan src/ --out plan.json # write it for review / CI artifact
scion plan src/ --run # plan AND drain it through ladder + Gate--run executes a MUTATING plan, so senior review blocks it until a
fingerprint-bound sign-off exists: the first --run prints the review and
returns awaiting-approval (exit 1), and scion plan src/ --run --approve-as
<reviewer> mints the signature for exactly those bytes and drains it. Any
edit to the plan voids the approval.
Because the manifest is a regular workflow, resumability applies for free:
a halted --run re-drives from the same findings (or the written manifest)
and only the incomplete suffix executes. The plan is deterministic — same
tree, byte-identical manifest, stable fingerprint.
Parallel batches
The plan exposes cross-file independence explicitly: batches holds the
parallel waves (wave i = the i-th fix of every file — derived from the same
depends_on edges, so batches and graph can never disagree), and
max_parallel is the widest wave. scion plan <target> --run
--concurrency N (and scion workflow <file> --concurrency N) runs up to N
ready steps at once. Wave outcomes are applied in selection order — never
completion order — so summaries stay deterministic; any failure or
escalation stops new launches, records its wave siblings' real outcomes,
and blocks downstream exactly as the sequential scheduler does.
--concurrency 1 (the default) is the strict sequential behavior.
DAG workflows (scion workflow <manifest.json>)
A JSON manifest describes tasks with manifest-local ids and depends_on
edges (forward references legal, cycles rejected with the offending members,
Kahn-validated before anything is enqueued):
{
"name": "clean-module",
"tasks": [
{ "id": "strip-var", "kind": "fix:var-declaration",
"payload": { "text": "var at line 1", "file": "src/a.js", "line": 1 } },
{ "id": "strip-log", "kind": "fix:console-log-residue",
"payload": { "text": "log at line 2", "file": "src/a.js", "line": 2 },
"depends_on": ["strip-var"] }
]
}The whole graph is enqueued up front — depends_on gates claiming exactly
as the queue enforces it — then drained to completion: claim → ladder →
apply → Gate → learn, per task. A dependency failure halts the drain
and reports downstream tasks as blocked (still pending, zero retry burn);
escalations halt the same way. The summary reports { total, completed,
failed, escalated, blocked, status, tasks[] } per manifest id, and the CLI
exits non-zero unless status is completed (CI-friendly).
Sequenced patches are the point: task 2 can safely target a line task 1 just
changed, because the dependency edge guarantees ordering — proven live with a
three-patch chain (var→let → log strip → debugger strip) applied to one
file in a single scion workflow run.
Pre-flight senior review. A manifest whose steps can WRITE blocks before
any enqueue or execution — a task step's risk is read from its declared write
surface (file | files | filePatch | fileRewrite | content | cmd | generate,
src/kernel/manifest.js), never the file field alone, and a command named
in a payload goes through the same command classifier the shell step uses
(worst class wins). Shell steps and kernel calls are mutating at most:
scion workflow wf.json returns status: "awaiting-approval" with the full
plan surface (risk per step, exact commands redacted) — nothing has run,
no queue rows exist. The human re-runs with --approve-as <reviewer> to
sign; the approval is bound to the manifest FINGERPRINT, so any plan edit
voids it and the next drive re-blocks. The audit chain joins on one
fingerprint: workflow.awaiting-approval → senior-review.approved (with
reviewer) → workflow.start → workflow.done. Read-only plans — every step
declaring no write surface — run without ceremony, and the worker enforces the
same declaration (a task that names a target but applies nothing fails loud
instead of completing as a verified no-op). Native steps beyond queue tasks: shell (gated
commands, exit-code oracle, Gate-shaped evidence), call (whitelisted
kernel functions), ocr (perception adapter) — all journaled as
workflow.native-step and resumable from the ledger like queue tasks.
Role binding: scion workflow wf.json --role reviewer executes task steps
with that role's capability filter applied inside the atomic claim;
an unknown role fails loud pre-enqueue. The daemon's auto_fix opt-in
flag is the standing approval for the fix plans it drives (journaled as
senior-review.approved with reviewer daemon:autoFix (opt-in)).
Native step types: shell and call
Beyond queue tasks, a manifest can carry native steps that run without
enqueue/claim/ladder — but are gated the same way: every verdict is
Gate-shaped evidence (verified, commands, exit_codes), every failure
halts the drain, and every outcome is journaled and ledger-tracked:
{
"name": "release-prep",
"tasks": [
{ "id": "check", "type": "shell", "cmd": "node --check src/index.js", "timeout_ms": 5000 },
{ "id": "learn", "type": "call", "fn": "boostConsensus", "depends_on": ["check"] },
{ "id": "report", "kind": "report", "payload": { "text": "summarize the release" },
"depends_on": ["learn"] }
]
}shell—{ cmd, cwd?, timeout_ms? }run through the same blocklist-gated command runner the Gate verifier uses: fork bombs,rm -rf /, andcurl | share a failed step, never a silent pass; output is captured and redacted; judged by exit code.call—{ fn, args? }invokes a whitelisted kernel function (forge,analyze,reason,remember,boostConsensus,dailyMaintenance); anything outside the whitelist fails loudly naming the callable surface — no arbitrary code execution through manifests.
The scheduler is unified: a queue task can depend on a native step and vice
versa, and edges are enforced across both kinds. Native steps resume from the
ledger exactly like tasks (a re-drive reports them skipped: true, zero
re-execution), and their outcomes live in the run ledger — durable, not
in-memory.
Resumability
Every run is fingerprinted (canonical SHA-256 of the manifest graph — the
same canonicalizer the evidence certificates use) and recorded in a
persistent run ledger (workflow_runs in the brain's SQLite). Re-driving the
same manifest file — in this process, next week, or from another machine on
the shared DB — resumes the run: only the incomplete suffix executes.
Completed tasks are reported from the ledger with skipped: true and cost
nothing; escalated tasks stay in the review lane until the human settles
them, and their resolution counts when the run is re-driven. A halted run
keeps its ledger entry OPEN (survives crashes and restarts); a fully
completed run closes it. scion workflow <file> --fresh discards the old
entry and re-runs everything.
Quick start
npm test # the full suite
node bin/scion.js # interactive REPL
node bin/scion.js run "add a clamp to foo.js" # one task through the ladder
node bin/scion.js workflow wf.json # a whole DAG: enqueue → drain → summary
node bin/scion.js swarm 3 # 3-worker parallel swarm, same kernel
node bin/scion.js economy # token-economy report
node bin/scion.js brain # brain stats (memories, relations)
node bin/scion.js remember "Chose SQLite because it needs zero setup"
node bin/scion.js search "rate limit"
node bin/scion.js reason "http" # 6-mode deterministic inference
node bin/scion.js serve 5107 # HTTP API + daily maintenance loop
node bin/scion.js serve 5107 --follower --lease-ms 2000 # standby (failover tier)
node bin/scion.js leader # who holds the serve lease on this DB
node bin/scion.js doctor --strict # production-readiness gate (probes, not opinions)
node bin/scion.js learn trend # is FS improving? (ledger-backed deltas)
node bin/scion.js tools earn # which tools earn their keep (the tool ledger)
node bin/scion.js tools trend # earn rates over time (the ledger's time dimension)
node bin/scion.js tools pools # cross-registry: specialist or generalist?
node bin/scion.js tools playbooks # tool chains LEARNED from the trail
node bin/scion.js plans # tasks frozen awaiting operator approval
node bin/scion.js approve t12 --as you # planned → pending (claimable)
node bin/scion.js checkpoints list t12 # the restore timeline for a task
node bin/scion.js memory forget 7 # soft-delete a brain memory (journaled)
node bin/scion.js review pr --patch fix.diff # inbound diff through the real Gate
node bin/scion.js events --follow # the versioned event feed, NDJSON, stable envelope
node bin/scion.js audit --since 24h --action refused --csv # what was refused/failed, exportable
node bin/scion.js compact t12 # the bounded view of a task's context (zero model calls)
npm run verify # boundaries + suite gate (counts, dead files) before you pushProduction runbook — the daily cycle (v0.4.0)
FS runs as an always-on, self-improving agent. Full guide: docs/PRODUCTION.md.
The head-to-head case against LLM-backed agents — same capabilities, zero token
bill, evidence that compounds — is docs/PARITY.md.
The short form:
# config/scion.config.yaml — the daily posture
cron:
- name: overnight-sweep
schedule: '@daily' # 'HH:MM' | '@hourly' | '@daily' | '@startup'
kind: agent # REQUIRED — a clock that enqueues nothing is decoration
payload: { text: 'scan repo for transformable findings and enqueue fixes' }
scheduler:
max_consecutive_failures: 5 # a schedule whose task keeps FAILING disables
# itself and says why (0 = no breaker)
goals:
enabled: true
declared:
- goal: 'keep the test suite green on main'
sources: [diagnostics]
notify:
webhook_url: https://your-hook.example/scionThen scion doctor --strict → READY, scion serve, and the loop is live:
- LEARN — every task outcome (success AND failure) feeds the loop; the
learn-cycle (every 6h by default,
learn.auto) mines weaknesses, gate-verifies harness edits, forges seeds, and ledgers the vitals. - MEASURE —
scion learn trendshows pass-rate deltas;scion economyshows the deterministic share;scion rungsshows which rung RESOLVED the tasks it was given and what that cost (tokens_est_per_resolved, plus the spend on the tasks it handed off); the pool and tool ledgers show what earns its keep (see below). - IMPROVE — only gate-verified outcomes enter replay/skills/edits; the trend is a measured number, never a claim.
What earns its bytes: the two ledgers (v0.4.0)
- Pool analytics (
GET /ui/pool/analytics, Pool view → Earn-rate panel): every dispatch attributes task outcomes to the pooled entries that rode it;earn_rate = solved / (solved + burden)per entry, bytes-per-solve for byte efficiency. The gate is the only credit — escalations and failures count as burden. - Tool earn (
scion tools earn,GET /ui/tools/earn): the same ledger for the tool registry.research()now selects tools by measured earn rate (unproven tools ride mid-rank, never punished; proven zero-yield tools are skipped), runs chain playbooks for known problem families (git-state, dependency-probe — later steps see earlier stdout), and self-checks: incomplete coverage triggers a bounded replan (max 2 passes) with gap-targeted fill runs instead of an escalation shrug.
Both ledgers ride the learn-loop vitals, so the daily cycle measures its own knowledge and its own hands.
The readiness gate (scion doctor)
doctor: READY (10/10 checks pass)
✓ database: 52 tables
✓ trail: hash chain intact (619 events)
✓ learn_loop: auto-cycle every 360 min · 4 cycle(s) run
✓ autonomy: 2 cron schedule(s) · 1 standing goal(s)
✓ notify: webhook armed — escalations reach a human
✓ forge: min_support 3 · precision floor 0.7
✓ bounds: max_turns 25 · timeout_ms 300000 · approval required
✓ hooks: onGatePass×1, onEscalation×1 (timeout 10000ms)
✓ executor: process backend — verifier commands run in-process
✓ plan_gate: approval: required — plans freeze until approved--strict additionally requires the daily cycle ON, so READY means improvement
is actually running. Same verdict at GET /doctor?strict=1 for fleet monitors.
HTTP API (scion serve)
Zero-dependency (node:http) surface for CI/CD, dashboards, and remote
operators — every route is a thin shell over the same kernel the CLI uses:
GET /health liveness (always open)
GET /stats queue + brain + replay + token economy
GET /tasks queue snapshot
POST /tasks enqueue { kind, payload, bounds?, priority? }
GET /review escalation review list
POST /review/<id>/resolve { verdict: approve|reject|defer, fix?, reviewer? }
GET /replay/conflicts CoRE-flagged verdicts (conflicts > 0)
POST /replay/conflicts/clear { sig? } — settle one or all conflicts
POST /replay/boost-consensus run the maj@n consensus pass now
GET /trail[?kind=…] journaled events
GET /ui/events[?kind=&origin=&since_seq=&limit=] the versioned feed (JSON + cursor)
GET /ui/events/stream the same envelope over SSE: catch-up, then live
GET /ui/events/info the wire contract (version, envelope, surfaces)
GET /seeds · GET /replay mind introspection
GET /doctor[?strict=1] production-readiness verdict (probe-backed)
GET /ui/pool · /ui/pool/carried the knowledge pool as a metered surface
GET /ui/pool/analytics what earns its bytes (pool ledger)
GET /ui/tools/earn what earns its keep (tool ledger)
GET /ui/tools/trend earn rates over time (day-bucketed)
GET /ui/tools/cross-registry per-pool earn profiles (specialist vs generalist)
GET /ui/playbooks tool chains learned from the trail
GET /ui/memory[/<id>] brain memory inventory (operator CRUD)
POST /ui/memory/<id>/forget soft-delete a memory { hard?: bool }
GET /plans tasks frozen awaiting operator approval
POST /tasks/<id>/approve planned → pending { approver?, note? }
POST /tasks/<id>/reject planned → escalated { approver?, reason? }
GET /tasks/<id>/checkpoints the restore timeline for a task
POST /tasks/<id>/checkpoints/<seq>/restore byte-exact restore
POST /review/pr inbound diff through the real Gate { patch }
GET /ui/cron · /ui/goals the autonomy clock + standing goals
POST /ui/cron/<name>/enabled re-arm or stand a schedule down { enabled }
GET /ui/browser web-operation posture + who is driving (lease)
POST /ui/browser/takeover a HUMAN takes the page { minutes?, ms?, by? }
POST /ui/browser/release hand it back (idempotent)Watching FS work from outside (the event feed + the audit view)
The journal is the durable record, but a durable record nobody can read from outside is a log file. Two surfaces make it a contract — and both are pinned by tests, so neither can drift from the trail it describes:
scion events— the journal through one stable envelope ({ v, seq, ts, iso, kind, origin, data }), as NDJSON for scripts and log shippers,--jsonfor a page with its resumable--since-seqcursor, and--followfor a live tail.--infoprints the wire contract; an uncatalogued--kindis a loud exit 2 that names the near misses (family-first, deterministic — never a fuzzy guess) instead of returning silent emptiness. The same feed is at/ui/events(JSON) and/ui/events/stream(SSE: catch-up from your cursor, then live, one envelope, no gap).scion audit— the operator's question answered directly: what did the harness refuse, what failed, and why? Classification is total over the event catalog (a decision →refused, an outcome →failed/event, a kind that does not say how it ended is read from its data), the initiator is derived (a schedule is not an operator), and--csvexports the same rows with stable columns. The human summary counts every filtered row while the cap hides the tail — an honest cap, never a silent truncation.
node bin/scion.js events --kind task.failed --since 1h --follow
node bin/scion.js events --info | head -20 # version, envelope, surfaces
node bin/scion.js audit --since 7d --kind gate.verify --json
node bin/scion.js audit --action refused --csv > refusals.csvA bounded context (scion compact) and the suite gate (npm run verify)
Two gates that came out of studying a hosted agent stack, rebuilt so they hold without a model in the loop (the full study, with what was rejected and why, is research/freebuff_lessons.md):
- Deterministic compaction (src/mind/compact.js) — a
task's working set plus its own payload become a view under
compact.max_bytes. The live request stays verbatim; declared outcomes are never summarised, and if they do not fit the organ refuses and hands back the verbatim text instead of quietly dropping an exit code; references keep a head, notes collapse to named outlines, and anything left out is listed in anomittedsection. Measured against the verbatim text, a rewrite that does not shrink is a journaled no-op. Pure and byte-deterministic: the working set is the record and is never mutated. - The suite gate (scripts/verify-suite.mjs) —
npm run verifyruns the boundary gate and then the suite, judging it against a committed baseline: a drop in tests or files is refused with its delta named, an unparsed total is unknown (never a pass), a*.test.jsthat calls notest()is named as dead weight, and--updaterefuses to re-record a baseline from a run that was not green.
node scripts/verify-suite.mjs --json # the receipt, for CI
node scripts/verify-suite.mjs --update # re-record (prints the delta)
node scripts/verify-suite.mjs --min-tests 900 # a floor for this pushCI integration (GitHub Action)
.github/workflows/scion-gate.yml runs on every push/PR:
- Suite + bench — the project's own Gate first (
npm test,npm run bench) - Analyze + fix —
scripts/ci-fix.mjsruns the queue→ladder→Gate pipeline oversrc/with a real exit-code oracle (node --checkon the touched modules) - PR evidence comment —
reports/evidence.mdposted sticky on the PR: findings by rule/severity, per-fix outcome, and the SHA-256 certificate digest of every verified fix - Commit-back — verified fixes are pushed by
scion-gate[bot]with the digests preserved inreports/fixes.json - Artifacts — findings/fixes/evidence uploaded for offline audit; an
auditor can sign the cert with
SCION_CERT_PRIVATE_KEYand anyone canscion-cert verifyit without repo access
node scripts/ci-fix.mjs --target src --out reports [--dry-run] [--max 20]Exit 0 = all fixes verified; exit 1 = any gate failure (CI flags it).
Image perception — deterministic OCR (rung 0)
Scion can now SEE the text inside images (listing photos, screenshots, scanned specs) without breaking the zero-generation doctrine: an image's TEXT layer is a mechanical property, so extracting it is deterministic work, not model guessing.
src/mind/ocr.js— the adapter. Shells out to thetesseractCLI (exit-code judged through the same blocklist-gated command runner as the Gate verifier), records the engine, token count, and the image's SHA-256 as evidence. No engine installed → loud refusal, never fake or empty text. Anengine:injection seam (like gateverifyFn) lets embedders with a working OCR runtime plug it in.- Ladder rung 0 — a problem shaped
{ image: 'photo.jpg' }gets its text layer extracted once and joins the ladder as ordinary text: the analyzer, seeds, memory, and reasoner rungs all work on it unchanged. The extraction (or refusal) is journaled (ladder.ocr/ladder.ocr-refused). OCR refused + no other signal → escalate, honestly. - Workflow step —
{ type: 'ocr', image, opts? }is a native step: validation is pre-enqueue, a missing engine is a FAILED step carrying the refusal (halts the run), and extracted text lands in the evidencedetail. Also callable as kernel fnocrImage.
What this does NOT do: semantic image understanding ("scratched", color, condition beyond its text labels) still needs a vision model. That would be an opt-in, budgeted rung following the same candidate-only contract as the LLM rung — off by default.
Natural-language understanding — deterministic NLU (rung −1)
Humans speak INTENT; the ladder's rungs match TEXT. src/mind/nlu.js is
the seam, entirely mechanical — lexicons, templates, suffix folding,
stopword removal — no model anywhere:
- Normalizer — lowercase, strip punctuation, fold suffixes
(
logs→log,logging→log,queries→query), drop stopwords → one canonical key. "Fix the login bug!" and "fix login bugs" collapse tofix login bug. - Intent classifier with slot extraction — verb lexicon
(
fix/plan/show/search/remember/analyze/explain/run/task), question detection (wh-words/auxiliaries), and slots: file paths (validated withexistsSync), quoted spans, deadline phrases (by Friday,in 2 days,eod), priority words. Output:{ intent, target, slots, canonical, confidence, alternatives }. - CLI-verb routing —
scion run "show me the trail"routes to the trail,"remember that X"saves a memory,"search for X"searches the brain. Questions and ambiguous utterances surface a clarification (top-N interpretations) instead of becoming a doomed queue task. Every interpretation is journaled (nlu.interpret/nlu.clarify): why the system understood what it understood is always auditable. - Synonym expansion — a small CONTROLLED table (data, not code),
symmetric and stem-aware (
log↔logging↔logs). Seed triggers and memory searches expand through it, so a seed forged on "log" fires on "logging output" and vice versa. - Paraphrase replay — verified verdicts are additionally aliased
under their canonical-form signature (
replay_aliasestable): a paraphrase of a learned problem replays at zero generation cost, with confidence damped 0.9× (phrasing differed, so trust is discounted). File tasks never canonicalize — their payload pins exact source state. - Benchmark —
npm run nlu:bench: planted utterances scored per intent (P/R/F1) plus question detection and slot accuracy. The layer cannot silently regress.
The clarification loop — an ambiguous utterance (no intent evidence,
or evidence for several intents) is neither escalated cold nor silently
guessed. It asks ONE deterministic question with the top-N ranked
interpretations (ranked by evidence count, ties by lexicon precedence —
same utterance, same question, always), and the answer resolves three
ways: the option number ("2"), the intent word ("the fix one",
"fixes"` — fold-aware), or a rephrased utterance (re-driven through
the loop, depth-capped at 3). Surfaces:
- Interactive REPL — asks and re-asks through the readline.
- One-shot on a TTY (
scion run "…") — asks once via a throwaway readline, then proceeds. - Non-TTY (scripts/CI) — never blocks: returns
{ ok:false, intent:'clarify', prompt, options }with exit code 2 so the caller can answer (or re-run with--intent) later. scion run "…" --intent fix— forces the interpretation up front: deterministic for automation, no question ever asked.
Scoped vocabularies — domain contexts activate additional lexicon
layers of namespaced intents (git.commit, git.rebase, test.run,
test.coverage, deploy.release, deploy.rollback, …). Two ways to
activate:
scion run "…" --scope git— the flag turns the vocabulary on for the utterance ("commit the changes"→git.commitinstead of a generic task).- Inline
@scopetokens —"@git revert the last commit"activates the vocabulary from within the utterance itself; the token is stripped and the active scope is echoed on the interpretation (and journaled). Unknown@tokens(@alice) are left untouched — they may be real content.
Precedence is sound by construction: scoped entries compete with core
verbs by earliest utterance position (domain context is more specific),
generic verbs only fill the void, wh-words are structural question
evidence rather than lexicon, unknown scopes fail loud (a silently
inert scope would quietly misinterpret every domain utterance), and a
scope is strictly additive — with no scoped word present, core verbs
and learned terms behave exactly as off-scope. Per-scope benchmark
fixtures (positive, core-preserving, and cross-scope controls) pin this
in npm run nlu:bench.
Per-project auto-activation — a project's brain REMEMBERS which
vocabularies are active for it (persisted under the brain's meta
nlu_scopes key), so scion run "commit the changes" understands git
verbs with no flag at all:
scion scopes— list the project's active scopes.scion scopes add git— activate a vocabulary (additive, idempotent; unknown names fail loud).scion scopes rm git— deactivate (removing a never-active scope fails loud — silence would leave the operator misinformed).
Resolution is one deterministic merge (resolveScopes): inline @scope
tokens, then an explicit --scope flag, then the project defaults — all
additive and deduped, and every journal entry records which sources were
active (scope + projectScopes) so audit always shows why a domain
verb was understood.
Every question, answer, and resolution is journaled (nlu.clarify /
nlu.resolve) alongside nlu.interpret.
The lexicon learns from the misses — every clarification is persisted
as an NLU gap candidate (nlu_gaps table, one row per canonical
utterance; repeats grow seen_count, so frequency is evidence, not
noise). When a human answers the question, the answer TEACHES the
lexicon: the utterance's missed content terms are mapped to the chosen
intent, and the interpreter consults those learned terms — so the next
identical phrasing interprets correctly and never asks again. Learned
terms only fill the VOID: the curated static lexicon always wins first,
so teaching "ship the login module" → run cannot turn "fix the login
bug" into a run task. Management surfaces:
- Review phase 2 (
scion review -i) — after the decisions queue, the session lists open gaps (most-asked first) and teaches by intent name. scion gaps— list open gaps;scion gaps teach <id|utterance> <intent>;scion gaps forget <id>reopens a mapping that proved wrong (the phrasing asks again);scion gaps --allshows the full ledger.
Honest ceiling: without a model, vocabulary is finite — utterances outside the lexicon escalate or ask for clarification. That is the doctrine working, not failing.
Rule pack growth: ESM import hygiene + async error handling (32 rules)
require-assign—const x = require('m')→import x from 'm';(exact transform, gate-verified).module-exports—module.exports = X→export default X;.exports-dot-assign—exports.name = V→export const name = V;.async-no-try— an async function whose body has no try/catch (the rule carries awhen(source, line)context validator so the header line sees its whole body — flagged only when genuinely unguarded); fixed by thewrap-async-try-catchcodemod: bracket-matched, structure-aware wrap that reindents the body, skips already-guarded functions, is idempotent, and produces node-parseable output (suite-checked).unhandled-promise-then— a.then()statement with no.catch()tail (catch-tailed chains are spared).
Cross-bench effect (npm run bench:cross): FS detection on the
async/import fixture went 0/2 → 2/2 and FS fix completion sits at 93%
overall (measured; it was 65% before empty-transform lines were
deleted outright instead of left as blank husks), extending the lead
over persona (62%) and cortex (14%) on the same fixtures and scoring
weights. The bench also runs an escalation→teach→refix loop on a shape
no rule covers: fix-rate growth across generations is measured there
(cold gen → dossiers taught through the real channel → crystal promoted
→ next-gen re-run through analyze), not asserted.
Inherited capabilities (cortex-os-agent grafts, Tiers 1–2)
scion ship <signed-cert.json> <files...> [--push] [--pr]— git-native delivery of VERIFIED fixes: the signed evidence certificate must verify (signature, digest, all verdicts green), then branch → commit with the cert digest in the message → push/PR (explicit-only; a push is never a side effect). Re-ship after partial failure resumes the branch.- Codemods (
src/mind/codemods.js) — structure-aware transforms: a string/comment-aware scanner with bracket matching, plusjson-parse-guard(wraps JSON.parse statements in rethrowing try/catch) andany-to-unknown(TS retype). Refuse-don't-guess: no target shape, no change. Outputs are candidates — the Gate still disposes. scion curate <dir>— the codebase model (cortex curator lineage, zero-dep): exports/functions/imports per file, dependency edges, persisted in the brain with per-file content hashes (freshFilesreports staleness), Mermaid dependency graph (--mermaid), and deterministic test scaffolds (--scaffold <file>) — themselves gate-verifiable artifacts.scion conventions— project-local convention discovery as EVIDENCE, not verdicts: dominant quotes/semicolons/indent/no-var with a prevalence floor (≥0.8 over ≥30 samples; a split is noise, not a convention).scion conventions <file>reports a file's deviations — ladder/analyzer material, never a failing verdict.scion novelty— the machine-proposal inbox: durable, deduped proposals (seeds, verifier recipes, analyzer rules) from generators; adoption is a separate human gate, so invention never bypasses review.- Roles (
src/kernel/roles.js) — capability routing: tasks may declare requiredcapabilities; workers boot as ONE role; the claim filter runs inside the queue's atomic transaction; unclaimable work is NAMED loudly (unclaimableReason) instead of starving silently. - Senior review (
src/gate/senior-review.js) — pre-flight sign-off for workflows: deterministic risk classification (destructive / mutating / read-only), a plan surface a human can approve, and the approval bound to the manifest FINGERPRINT — edit the plan, void the signature. Read-only plans need no ceremony.
Recipe library — gate any stack with one config include (scion recipes)
Gate verifier BUNDLES per stack ship in recipes/ as pure data (YAML —
description, required tools, verifier commands): node (node --check +
npm test), python (py_compile + pytest), go (gofmt discipline +
go vet + go test), rust (cargo check + clippy discipline + cargo test),
dotnet (dotnet build + test), jvm (wrapper-aware Maven/Gradle test),
docker (image build), terraform (fmt -check + init + validate —
deliberately read-only; plan/apply belong in senior-review-approved workflow
steps, never a gate), xcode (xcodebuild, tuned by SCION_XCODE_* env),
gradle (wrapper build + test). POSIX-pipeline verifiers declare
shell: bash and run under Git Bash on Windows. Enable with one line:
gate:
recipes: [node] # add python, docker… — bundles concatenate in orderHand-written gate.verifiers still run AFTER recipe bundles (project-specific
checks last), and an explicit list always wins. {file} placeholders expand
per-file exactly as before. Every recipe command crosses the same safety
blocklist and exit-code oracle as hand-written ones — a recipe is
configuration, never a bypass.
scion recipes # list the library + what's active in config
scion recipes doctor # probe each recipe's tools on THIS machine (exit 1 if missing)
scion recipes show terraformThe doctor runs tool --version per required tool before anything executes:
a missing terraform/xcodebuild/gradle is a loud pre-flight report, never a
mid-gate spawn failure.
Architecture enforcement (scion arch + architecture.rules)
The curator's symbol graph grows into an ARCHITECTURE ENFORCER: you declare
your layer graph and dependency direction in config, and FS checks the real
import graph against the declaration. Deterministic, zero-dep, no LLM —
an infra/ module importing from domain/ is a systemic sin no line
scanner can see, but the dependency graph sees it exactly.
architecture:
rules:
- deny: [[src/infra, src/adapters], [src/domain]] # infra must not import domain
- deny: [[src/domain], [src/infra]]
allow: [[src/domain/ports], []] # explicit exceptionRules are path-segment-sound (src/dom never matches src/domain/…),
matched against project-root-relative paths, and validated at load — a
typo fails loud instead of silently disabling enforcement. Violations come
out as analyzer-shaped findings (arch-layer-violation, severity error,
exact file:line + import statement), so they ride every existing surface:
scion analyze, scion arch (dedicated report, CI-exit non-zero), the CI
evidence bundle, scion watch scans, and the MCP scion_analyze tool.
The doctrine line: arch violations are design decisions, so they are
never auto-patched. The planner excludes them; scion arch --enqueue
puts them through the ladder's ARCH rung, which resolves to an escalation
with the violation evidence attached — the human chooses refactor, move,
or amend the declaration, via the same scion review loop as every other
escalation.
Hub rules — shape, not just edges (architecture.hubs)
Edges police direction; HUBS police concentration, checked against the
schematic's measured fan-in/fan-out (scion map design data — curator
models derive the same numbers from edges, so no map build is required):
architecture:
hubs:
max_fan_in: 100 # no file imported by more than N (change magnets)
max_fan_out: 20 # no file importing more than N (God modules)
max_layer_fan_in: 300 # no layer funneling more inbound edges than N
ignore: [vendor, gen] # path prefixes exempt from hub accountingHub violations are analyzer-shaped warnings (arch-hub-fan-in,
arch-hub-fan-out, arch-hub-layer-fan-in) carrying the measured number,
the declared ceiling, and the file — a design smell escalates to the human
arch lane, never machine-patched. All thresholds are opt-in (empty = not
checked); malformed or typo'd keys fail loud. Live on FS's own source at
diagnostic thresholds: kernel/trail.js flagged at 173 inbound edges
(change magnet), daemon.js at 22 imports (God module).
Map-first THINK (schematic.enabled)
Every ladder decision attaches the schematic digest — layers, entries,
hubs, exported surface — as context for all downstream rungs (generator
prompts, analyzer reasoning, research queries). Served from a warm cache
(schematic.digest_ttl_ms, default 30000) so latency-bounded scans are
never starved: one refresh per TTL window, amortized across every worker
and daemon scan. taskId and mapContext are ambient keys — stripped
before signature hashing, so identical problems replay identically across
task ids and map refreshes.
Command over tools — the research rung (scion tools)
FS's rung
