npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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 verify adds 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 --update refusing 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-sensitive journal(, 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 spec turns a feature name into the three reviewable artifacts (requirements → design → tasks) and compile puts the open tasks on the queue, where the Gate judges them like any other work; scion plugins installs, lists and loads declared plugins (a directory with scion-plugin.json and a register(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 journals http, not cli, so trail.bySurface() tells the truth. The journal is finally readable from OUTSIDE the UI: scion events speaks one versioned envelope (NDJSON for scripts, --follow for a live tail, --info for the contract, and a LOUD exit 2 naming near misses for an uncatalogued kind) over the same /ui/events + /ui/events/stream routes, and scion audit answers what the harness refused, what failed and why — filterable, --csv-exportable, with a cap that states what it hides. And 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. 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), so scion acquire [status|fix|server|model <id>] reconstructs the stack (exit 1 = gaps, script-gateable), llm.server.acquire.auto: true fills gaps at first required use, and scion doctor grew an llm probe 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, plus scion 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 downloaded

scion 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-scion

That 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 inventory

Complete 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 acquire prints the availability matrix and exits 1 while incomplete (scripts gate on it; not an error). scion acquire fix fills every gap it can: server archive → install_dir, served GGUF → its catalog download. server / model <id> fetch one piece, and hf <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, mmproj projectors) 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. Default false keeps the zero-LLM posture — an installed FS stays inert until asked.
  • scion doctor grew an llm probe — 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.gz actually reaches tar on POSIX; before, everything was named .zip), both residue names are cleaned, and modelIdForPath() maps a served GGUF back to its catalog id so errors say scion 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 along

Three 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 id
  • scion acquire hf <id> — any GGUF, with or without a catalog entry. @file.gguf pins the filename; the id alone picks Q4_K_M first (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 HF id 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 says HF_TOKEN (private/gated repos read it from the environment, never from config and never journaled), and an unknown @file lists 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 from scion 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 tasks

new 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-tools

serve 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              # alias

The 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), or file_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+model dials 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 journals llm.route-error and 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) → declared speed_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 stay null — 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 --mmproj only 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: file resolves relative to the served model's directory (the ../<folder>/ form works from either sibling wheel), speed_tps is 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 --strict actually 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 by scripts/gen-events-map.mjs) with the capability contracts in docs/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 carries answer + cascade on the research candidate.
  • Learned playbooks drive tool selection — mined playbooks feed the research chain when built-in keywords miss (min_support declared), 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 (see demo/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: required and every mutating task freezes in status planned: claim-proof, invisible to workers, until you run scion approve <id> (or POST /tasks/<id>/approve). scion plans lists what awaits; scion reject <id> takes the escalation lane as a verdict. journal-only mode 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 receive SCION_HOOK_TASK and SCION_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: true makes 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?), and scion 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/memory routes: 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 swarm takes real tasks (free-text args or --manifest JSON) 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 explicit ttlDays) gets that lifespan on save; scion brain --sweep soft-deletes everything whose time has passed.
  • Supersession — saving a statement-like fact with a near-identical title (deploy is Monday over deploy is Friday) marks the old fact superseded_by the 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 exhausting vs pool exhaustion), retrieval falls back to vector-only. scion brain reports 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/ui

Windows 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>.exe

The 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 queue

Every 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 /, and curl | sh are 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 push

Production 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/scion

Then scion doctor --strict → READY, scion serve, and the loop is live:

  1. 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.
  2. MEASURE — scion learn trend shows pass-rate deltas; scion economy shows the deterministic share; scion rungs shows 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).
  3. 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, --json for a page with its resumable --since-seq cursor, and --follow for a live tail. --info prints the wire contract; an uncatalogued --kind is 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 --csv exports 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.csv

A 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 an omitted section. 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 verify runs 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.js that calls no test() is named as dead weight, and --update refuses 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 push

CI integration (GitHub Action)

.github/workflows/scion-gate.yml runs on every push/PR:

  1. Suite + bench — the project's own Gate first (npm test, npm run bench)
  2. Analyze + fix — scripts/ci-fix.mjs runs the queue→ladder→Gate pipeline over src/ with a real exit-code oracle (node --check on the touched modules)
  3. PR evidence comment — reports/evidence.md posted sticky on the PR: findings by rule/severity, per-fix outcome, and the SHA-256 certificate digest of every verified fix
  4. Commit-back — verified fixes are pushed by scion-gate[bot] with the digests preserved in reports/fixes.json
  5. Artifacts — findings/fixes/evidence uploaded for offline audit; an auditor can sign the cert with SCION_CERT_PRIVATE_KEY and anyone can scion-cert verify it 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 the tesseract CLI (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. An engine: injection seam (like gate verifyFn) 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 evidence detail. Also callable as kernel fn ocrImage.

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 to fix 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 with existsSync), 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_aliases table): 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.commit instead of a generic task).
  • Inline @scope tokens — "@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 --all shows 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 a when(source, line) context validator so the header line sees its whole body — flagged only when genuinely unguarded); fixed by the wrap-async-try-catch codemod: 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, plus json-parse-guard (wraps JSON.parse statements in rethrowing try/catch) and any-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 (freshFiles reports 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 required capabilities; 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 order

Hand-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 terraform

The 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 exception

Rules 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 accounting

Hub 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