swarm repositories / source
aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authormain <main@swarm.moe>2026-03-20 16:00:30 -0400
committermain <main@swarm.moe>2026-03-20 16:00:30 -0400
commit9d63844f3a28fde70b19500422f17379e99e588a (patch)
tree163cfbd65a8d3528346561410ef39eb1183a16f2 /README.md
parent22fe3d2ce7478450a1d7443c4ecbd85fd4c46716 (diff)
downloadfidget_spinner-9d63844f3a28fde70b19500422f17379e99e588a.zip
Refound Spinner as an austere frontier ledger
Diffstat (limited to 'README.md')
-rw-r--r--README.md448
1 files changed, 191 insertions, 257 deletions
diff --git a/README.md b/README.md
index 471fc9a..b2bd6cd 100644
--- a/README.md
+++ b/README.md
@@ -1,354 +1,288 @@
# Fidget Spinner
-Fidget Spinner is a local-first, agent-first experimental DAG for autonomous
-program optimization, source capture, and experiment adjudication.
-
-It is aimed at the ugly, practical problem of replacing sprawling experiment
-markdown in worktree-heavy optimization projects such as `libgrid` with a
-structured local system of record.
-
-The current shape is built around four ideas:
-
-- the DAG is canonical truth
-- frontier state is a derived projection
-- project payload schemas are local and flexible
-- core-path work is hypothesis-owned and experiment-gated
-
-## Current Scope
-
-Implemented today:
-
-- typed Rust core model
-- per-project SQLite store under `.fidget_spinner/`
-- project-local schema file
-- light-touch project field types: `string`, `numeric`, `boolean`, `timestamp`
-- hidden and visible node annotations
-- core-path and off-path node classes
-- CLI for local project work
-- hardened stdio MCP host via `mcp serve`
-- minimal web navigator via `ui serve`
-- replay-aware disposable MCP worker runtime
-- MCP health and telemetry tools
-- bundled `fidget-spinner` base skill
-- bundled `frontier-loop` specialization
-
-Not implemented yet:
-
-- long-lived daemon
-- full web UI
-- remote runners
-- strong markdown migration
-- cross-project indexing
+Fidget Spinner is a local-first frontier ledger for long-running optimization
+work.
+
+It is intentionally not a general research notebook. It is a hard scientific
+spine:
+
+- `frontier` is scope and grounding, not a graph node
+- `hypothesis` is a real graph vertex
+- `experiment` is a real graph vertex with one mandatory owning hypothesis
+- influence edges form a sparse DAG over that canonical tree spine
+- `artifact` is an external reference only; Spinner never reads artifact bodies
+
+The product goal is token austerity. `frontier.open` is the only sanctioned
+overview dump. Everything else should require deliberate traversal one object at
+a time.
+
+## Current Model
+
+The ledger has four first-class object families:
+
+- `frontier`
+ - a named scope
+ - owns one mutable `brief`
+ - partitions hypotheses and experiments
+- `hypothesis`
+ - terse claim or intervention
+ - title + summary + exactly one paragraph of body
+- `experiment`
+ - open or closed
+ - belongs to exactly one hypothesis
+ - may cite other hypotheses or experiments as influences
+ - when closed, stores dimensions, metrics, verdict, rationale, and optional analysis
+- `artifact`
+ - reference to an external document, link, log, plot, table, dump, or binary
+ - attaches to frontiers, hypotheses, or experiments
+ - only metadata and locator live in Spinner
+ - Spinner never reads the body
+
+There are no canonical freeform `note` or `source` nodes anymore. If a piece of
+text does not belong in a frontier brief, hypothesis, or experiment analysis, it
+probably belongs outside Spinner as an artifact.
+
+## Design Rules
+
+- `frontier.open` is the only overview surface.
+- No broad prose dumps in list-like tools.
+- Artifact bodies are never read through Spinner.
+- Live metrics are derived, not manually curated.
+- Selectors are permissive: UUID or slug, one field, no parallel `_id` / `_slug`.
+- Slow intentional graph walking is preferred to burning context on giant feeds.
## Local Install
Install the release CLI into `~/.local/bin` and refresh the bundled skill
-symlinks in `~/.codex/skills` with:
+symlinks in `~/.codex/skills`:
```bash
./scripts/install-local.sh
```
-Pass a different local install root or skill destination explicitly if needed:
-
-```bash
-./scripts/install-local.sh /tmp/fidget-local /tmp/codex-skills
-```
+The installed binary is `~/.local/bin/fidget-spinner-cli`.
## Quickstart
-Initialize the current directory as a Fidget Spinner project:
+Initialize a project:
```bash
-cargo run -p fidget-spinner-cli -- init --project . --name fidget-spinner --namespace local.fidget-spinner
-```
-
-Create a frontier:
-
-```bash
-cargo run -p fidget-spinner-cli -- frontier init \
- --project . \
- --label "repo evolution" \
- --objective "improve the local MVP" \
- --contract-title "fidget spinner self-host frontier" \
- --benchmark-suite smoke \
- --promotion-criterion "cleaner and more capable" \
- --primary-metric-key research_value \
- --primary-metric-unit count \
- --primary-metric-objective maximize
+cargo run -p fidget-spinner-cli -- init --project . --name libgrid
```
-Register project-level metric and run-dimension vocabulary before recording a
-lot of experiments:
+Register the tag, metric, and run-dimension vocabulary before heavy ingest:
```bash
-cargo run -p fidget-spinner-cli -- schema upsert-field \
+cargo run -p fidget-spinner-cli -- tag add \
--project . \
- --name scenario \
- --class hypothesis \
- --class analysis \
- --presence recommended \
- --severity warning \
- --role projection-gate \
- --inference manual-only \
- --type string
+ --name root-conquest \
+ --description "Root-cash-out work"
```
```bash
cargo run -p fidget-spinner-cli -- metric define \
--project . \
- --key wall_clock_s \
- --unit seconds \
- --objective minimize \
- --description "elapsed wall time"
+ --key nodes_solved \
+ --unit count \
+ --objective maximize \
+ --visibility canonical \
+ --description "Solved search nodes on the target rail"
```
```bash
cargo run -p fidget-spinner-cli -- dimension define \
--project . \
- --key scenario \
- --type string \
- --description "workload family"
+ --key instance \
+ --value-type string \
+ --description "Workload slice"
```
+Create a frontier:
+
```bash
-cargo run -p fidget-spinner-cli -- dimension define \
+cargo run -p fidget-spinner-cli -- frontier create \
--project . \
- --key duration_s \
- --type numeric \
- --description "time budget in seconds"
+ --label "native mip" \
+ --objective "Drive braid-rail LP cash-out" \
+ --slug native-mip
```
-Record low-ceremony off-path work:
+Write the frontier brief:
```bash
-cargo run -p fidget-spinner-cli -- tag add \
+cargo run -p fidget-spinner-cli -- frontier update-brief \
--project . \
- --name dogfood/mvp \
- --description "Self-hosted MVP dogfood notes"
+ --frontier native-mip \
+ --situation "Root LP spend is understood; node-local LP churn is the active frontier."
```
+Record a hypothesis:
+
```bash
-cargo run -p fidget-spinner-cli -- source add \
+cargo run -p fidget-spinner-cli -- hypothesis record \
--project . \
- --title "next feature slate" \
- --summary "Investigate the next tranche of high-value product work." \
- --body "Investigate pruning, richer projections, and libgrid schema presets." \
- --tag dogfood/mvp
+ --frontier native-mip \
+ --slug node-local-loop \
+ --title "Node-local logical cut loop" \
+ --summary "Push cut cash-out below root." \
+ --body "Thread node-local logical cuts through native LP reoptimization so the same intervention can cash out below root on parity rails without corrupting root ownership semantics." \
+ --tag root-conquest
```
+Open an experiment:
+
```bash
-cargo run -p fidget-spinner-cli -- note quick \
+cargo run -p fidget-spinner-cli -- experiment open \
--project . \
- --title "first tagged note" \
- --summary "Tag-aware note capture is live." \
- --body "Tag-aware note capture is live." \
- --tag dogfood/mvp
+ --hypothesis node-local-loop \
+ --slug parity-20s \
+ --title "Parity rail 20s" \
+ --summary "Live challenger on the canonical braid slice." \
+ --tag root-conquest
```
-Record a core-path hypothesis and open an experiment against it:
+Close an experiment:
```bash
-cargo run -p fidget-spinner-cli -- hypothesis add \
+cargo run -p fidget-spinner-cli -- experiment close \
--project . \
- --frontier <frontier-id> \
- --title "inline metric table" \
- --summary "Rendering candidate metrics on cards will improve navigator utility." \
- --body "Surface experiment metrics and objective-aware deltas directly on change cards."
+ --experiment parity-20s \
+ --backend manual \
+ --argv matched-lp-site-traces \
+ --dimension instance=4x5-braid \
+ --primary-metric nodes_solved=273 \
+ --verdict accepted \
+ --rationale "Matched LP site traces isolate node reoptimization as the dominant native LP sink."
```
+Record an external artifact by reference:
+
```bash
-cargo run -p fidget-spinner-cli -- experiment open \
+cargo run -p fidget-spinner-cli -- artifact record \
--project . \
- --frontier <frontier-id> \
- --hypothesis-node <hypothesis-node-id> \
- --title "navigator metric card pass" \
- --summary "Evaluate inline metrics on experiment-bearing cards."
+ --kind document \
+ --slug lp-review-doc \
+ --label "LP review tranche" \
+ --summary "External markdown tranche." \
+ --locator /abs/path/to/review.md \
+ --attach hypothesis:node-local-loop
```
+Inspect live metrics:
+
```bash
-cargo run -p fidget-spinner-cli -- metric keys --project .
+cargo run -p fidget-spinner-cli -- metric keys --project . --frontier native-mip --scope live
```
```bash
cargo run -p fidget-spinner-cli -- metric best \
--project . \
- --key wall_clock_s \
- --dimension scenario=belt_4x5 \
- --dimension duration_s=60 \
- --source run-metric
+ --frontier native-mip \
+ --hypothesis node-local-loop \
+ --key nodes_solved
```
-Serve the local MCP surface in unbound mode:
+## MCP Surface
-```bash
-cargo run -p fidget-spinner-cli -- mcp serve
-```
-
-Serve the minimal local navigator:
+Serve the MCP host:
```bash
-cargo run -p fidget-spinner-cli -- ui serve --path . --bind 127.0.0.1:8913
+cargo run -p fidget-spinner-cli -- mcp serve
```
-`ui serve --path` is permissive: it accepts the project root, the
-`.fidget_spinner/` directory itself, descendants inside that directory, or a
-parent directory containing one unique descendant store.
-
-Then bind the session from the client with:
+If the host starts unbound, bind it with:
```json
{"name":"project.bind","arguments":{"path":"<project-root-or-nested-path>"}}
```
-If the target root is an existing empty directory, `project.bind` now
-bootstraps `.fidget_spinner/` automatically instead of requiring a separate
-`init` step. Non-empty uninitialized directories still fail rather than being
-guessed into existence.
-
-Install the bundled skills into Codex:
-
-```bash
-cargo run -p fidget-spinner-cli -- skill install
-```
-
-## Store Layout
-
-Each initialized project gets:
-
-```text
-.fidget_spinner/
- project.json
- schema.json
- state.sqlite
- blobs/
-```
-
-`schema.json` is the model-facing contract for project-local payload fields and
-their validation tiers. Fields may now optionally declare a light-touch
-`value_type` of `string`, `numeric`, `boolean`, or `timestamp`; mismatches are
-diagnostic warnings rather than ingest blockers.
-
-`.fidget_spinner/` is local state. In git-backed projects it usually belongs in
-`.gitignore` or `.git/info/exclude`.
-
-## Model-Facing Surface
-
-The current MCP tools are:
+The main model-facing tools are:
- `system.health`
- `system.telemetry`
- `project.bind`
- `project.status`
-- `project.schema`
-- `schema.field.upsert`
-- `schema.field.remove`
- `tag.add`
- `tag.list`
+- `frontier.create`
- `frontier.list`
-- `frontier.status`
-- `frontier.init`
-- `node.create`
+- `frontier.read`
+- `frontier.open`
+- `frontier.brief.update`
+- `frontier.history`
- `hypothesis.record`
+- `hypothesis.list`
+- `hypothesis.read`
+- `hypothesis.update`
+- `hypothesis.history`
- `experiment.open`
- `experiment.list`
- `experiment.read`
-- `node.list`
-- `node.read`
-- `node.annotate`
-- `node.archive`
-- `note.quick`
-- `source.record`
+- `experiment.update`
+- `experiment.close`
+- `experiment.history`
+- `artifact.record`
+- `artifact.list`
+- `artifact.read`
+- `artifact.update`
+- `artifact.history`
- `metric.define`
- `metric.keys`
- `metric.best`
-- `metric.migrate`
- `run.dimension.define`
- `run.dimension.list`
-- `experiment.close`
-- `skill.list`
-- `skill.show`
-
-Nontrivial MCP tools follow the shared presentation contract:
-
-- `render=porcelain|json` chooses terse text vs structured JSON rendering
-- `detail=concise|full` chooses triage payload vs widened detail
-- porcelain is default and is intentionally not just pretty-printed JSON
-
-Operationally, the MCP now runs as a stable host process that owns the public
-JSON-RPC session and delegates tool execution to an internal worker subprocess.
-Safe replay is only allowed for explicitly read-only operations and resources.
-Mutating tools are never auto-replayed after worker failure.
-
-Notes now require an explicit `tags` list. Tags are repo-local registry entries
-created with `tag.add`, each with a required human description. `note.quick`
-accepts `tags: []` when no existing tag applies, but the field itself is still
-mandatory so note classification is always conscious.
-
-`source.record` now also accepts optional `tags`, so rich imported documents
-can join the same campaign/subsystem index as terse notes without falling back
-to the generic escape hatch.
-
-`note.quick`, `source.record`, and generic `node create` for `note`/`source`
-now enforce the same strict prose split: `title` is terse identity, `summary`
-is the triage/search layer, and `body` holds the full text. List-like surfaces
-stay on `title` + `summary`; full prose is for explicit reads only.
-
-Schema authoring no longer has to happen by hand in `.fidget_spinner/schema.json`.
-The CLI exposes `schema upsert-field` / `schema remove-field`, and the MCP
-surface exposes the corresponding `schema.field.upsert` / `schema.field.remove`
-tools. The CLI uses space-separated subcommands; the MCP uses dotted tool names.
-
-Metrics and run dimensions are now project-level registries. Frontier contracts
-still declare the evaluation metric vocabulary, but closed experiments report
-only thin `key=value` metrics plus typed run dimensions. `metric.define` can
-enrich metric descriptions, CLI `dimension define` / MCP `run.dimension.define`
-preregister slicers such as `scenario` or `duration_s`, `metric.keys`
-discovers rankable numeric signals, and `metric.best` ranks one key within
-optional exact dimension filters.
-Legacy `benchmark_suite` data is normalized into a builtin string dimension on
-store open, and `metric.migrate` can be invoked explicitly as an idempotent
-repair pass.
-
-The intended flow is:
-
-1. inspect `system.health`
-2. `project.bind` to the target project root or any nested path inside it
-3. read `project.status`, `tag.list`, and `frontier.list`
-4. read `experiment.list` if the session may be resuming in-flight work
-5. read `project.schema` only when payload rules are actually relevant
-6. pull context from the DAG
-7. use `source.record` for documentary context and `note.quick` for atomic takeaways
-8. record a `hypothesis` before core-path work
-9. open the live experiment explicitly with `experiment.open`
-10. seal core-path work with `experiment.close`
-
-## Git And The Ledger
-
-Git remains useful for code history, bisect, and sensible commit messages, but
-the Fidget Spinner ledger is about the science rather than about reproducing git
-inside the experiment record.
-
-Core-path closure does not require a git-backed project. The canonical record is
-the hypothesis, run slice, parsed metrics, verdict, and rationale.
-
-## Workspace Layout
-
-- `crates/fidget-spinner-core`: domain model and invariants
-- `crates/fidget-spinner-store-sqlite`: per-project store and atomic writes
-- `crates/fidget-spinner-cli`: CLI plus hardened stdio MCP host and worker
-- `assets/codex-skills/fidget-spinner`: bundled base skill asset
-- `assets/codex-skills/frontier-loop`: bundled skill asset
-
-## Docs
-
-- [docs/product-spec.md](docs/product-spec.md)
-- [docs/architecture.md](docs/architecture.md)
-- [docs/libgrid-dogfood.md](docs/libgrid-dogfood.md)
-
-## Checks
+
+`frontier.open` is the grounding call. It returns:
+
+- frontier brief
+- active tags
+- live metric keys
+- active hypotheses with deduped current state
+- open experiments
+
+Everything deeper should be fetched by explicit selector.
+
+## Navigator
+
+Serve the local navigator:
```bash
-./check.py
-./check.py deep
+cargo run -p fidget-spinner-cli -- ui serve --path . --bind 127.0.0.1:8913
```
+
+`ui serve --path` accepts:
+
+- the project root
+- `.fidget_spinner/`
+- any descendant inside `.fidget_spinner/`
+- a parent containing exactly one descendant store
+
+The navigator mirrors the product philosophy:
+
+- root page lists frontiers
+- frontier page is the only overview
+- hypothesis / experiment / artifact pages are detail reads
+- local navigation happens card-to-card
+- artifact bodies are never surfaced
+
+## Store Layout
+
+Each initialized project gets:
+
+```text
+.fidget_spinner/
+ project.json
+ state.sqlite
+```
+
+In git-backed projects `.fidget_spinner/` normally belongs in `.gitignore` or
+`.git/info/exclude`.
+
+## Doctrine
+
+- hypotheses are short and disciplined
+- experiments carry the real scientific record
+- verdicts are explicit: `accepted`, `kept`, `parked`, `rejected`
+- artifacts keep large text and dumps off the token hot path
+- live metrics answer “what matters now?”, not “what has ever existed?”
+- the ledger is about experimental truth, not recreating git inside the database