IonGuide
G0 // Install and first runDry run by default

Guide

Run ion on your org, writing nothing.

Ion’s executors dry-run unless you pass --apply. Your first day with it should end with a dashboard full of proposals and an org that looks exactly as it did that morning. Approve later, on purpose, one plan at a time.

You need Python 3.12 or newer, uv, git with git subtree, the GitHub CLI gh logged in to an account that can see the org, and git-filter-repo if you want splits.

git clone https://github.com/aska-digital/ion.git && cd ion
uv sync                       # add --extra graph for Louvain clustering
cp ion.example.yml ion.yml    # then edit: org, maintainers, tracker_repo
uv run ion --config ion.yml doctor

doctor checks the GitHub login, git and subtree, filter-repo, the language-model backend, the bus if you use one, and the config itself. Fix what it names. Then take the first full pass. It reads, measures, files proposals in the tracker, and writes nothing to any other repo:

uv run ion --config ion.yml run          # the whole pipeline, executors dry-run
uv run ion --config ion.yml status       # what is waiting, held, done; any breaker trip
uv run ion --config ion.yml dashboard    # the Org health issue, or --print to just read it

State lives in ~/.ion/state.db and repo mirrors in ~/.ion/cache. Set ION_HOME to move both, and ION_CONFIG to set a default config path. Your real config, with maintainer names and local paths, belongs outside any public repo: ~/.ion/ion.yml is a good home.

Keep the tracker repo private. Proposal bodies name your private repos and quote their metadata. The default tracker name is ion-tracker. Create it as a private repo before the first run.

G1 // The config keys that matterion.example.yml is the full list

Start strict. Loosen one class at a time.

Every repo can override the org config in its own .github/ion.yml: who maintains it, whether ion governs it at all, and its policy action levels. Two settings shape your first month more than any others:

  • policy_strategy: opt-out (the default) governs every repo unless that repo says enabled: false. Choose opt-in to govern only repos that ask.
  • policy_actions sets, per policy class, what a drift finding does: log records it, issue proposes it and waits for approval, fix applies it unattended. Start everything at issue. Promote a class to fix only after its proposals have bored you for weeks. Structural kinds can never be fix.
KeyMeaning
orgThe organisation to steward
maintainersGitHub logins whose approval counts. Per-repo lists refine this
tracker_repoPrivate repo where proposals are filed as issues
approval_sourcesAny of github_label, divan_bus, dashboard
notifiersstdout, file, divan_bus, github_issue, webhook. Failed deliveries queue and retry
llm.backendnone (default), claude_cli or anthropic_api. Words only: the model cannot add repos or raise scores
guardsThe circuit breaker: max_repo_fraction, max_archives, max_writes, forbid_protection_lowering
writes.capsPer-run cap by write type, for example {open_pr: 5, archive_repo: 1}
quorum · approval_ttl_daysApprovers required per proposal, and when approvals expire (14 days)
lifecycledormant_days, plus repos or a topic that freeze the stale clock
boundariesTag rules and scope prefix. Cross-scope merges blocked by default
budget.graphql_points_per_runCollection stops cleanly at the budget (500) and resumes next run

Before adopting any change, preview it. ion plan-config NEW.yml runs both configs over the same snapshot and reports candidates gained and lost, drift changes, repos that would opt out, and open proposals that would be re-planned. It writes nothing.

uv run ion --config ion.yml plan-config candidate.yml
uv run ion --config ion.yml plan-config --set thresholds.merge_coupling=0.7
G2 // Approve your first planThe reviewer’s ten minutes

Read the case. Check the fingerprint. Decide.

  1. Open the proposal issue. It is titled like [P-0007] merge a into b in the tracker repo, labelled with its kind and state. Ion edits this one issue in place for the proposal’s whole life.
  2. Read the evidence, then the steps. The body lists the signals and scores, the ordered changesets with dependencies, the exact commands the executor will run, the rollback, and the blast radius. If any command surprises you, hold the proposal and ask why.
  3. Note the fingerprint. The plan-sha256: … line is the plan you are about to endorse. Your approval will count for that hash and no other.
  4. Decide on any channel. Add ion:approved, ion:hold or ion:rejected; or send ion approve P-0007 over the bus; or tick the box on the Org health issue. You must be a maintainer of every repo the plan touches, or your label is removed and logged as ignored.
  5. Let the next run execute, or run it yourself. ion execute --apply P-0007 re-derives your approval from the record, checks caps and the breaker, then works through the steps in order. A dependent step waits until the pull request before it has landed.
  6. Merge the pull requests yourself. Ion opens them on ion/* branches and proves the move before asking. It never merges its own work. If the plan ends with archiving the source repo, that arrives as a separate proposal needing a separate yes.
# What did ion do, and why does it believe it may?
uv run ion --config ion.yml explain P-0007   # ledger, approvals, steps, states
uv run ion --config ion.yml status           # queue, holds, last breaker trip

If new evidence changes a plan after you approved it, expect ion to ask again. The label comes off by itself. That is the system working, not a fault to work around.

G3 // Every commandSPEC §4

One pipeline, plus three tools you will use weekly.

ion collect | analyze | propose [--dry-run] | sync-approvals | execute [--apply] [P-0007]
ion report | run [--apply] | status | explain P-0007 | pause | resume | doctor
ion grep PATTERN [--path GLOB] [--repo GLOB] [-i] [-F]
ion autofix [NAME] [--repo GLOB] [--propose]
ion plan-config NEW.yml            (or --set key=value)
ion dashboard [--print]

ion grep

Search the whole org, free

Runs git grep over the default branch of every local mirror. No API calls, no writes. The fastest way to answer “where else does this pattern live?” before you propose changing it.

ion autofix

One small change, everywhere

With no flags it prints the diffs and writes nothing. With --propose it files one proposal whose fingerprint covers exactly those diffs. Pull requests exist only after approval, each recomputed and compared with what was approved. Built in: a readme skeleton and a Dependabot config generator. Write your own by subclassing ion.fleet.Autofixer.

ion plan-config

Try a rule before you live under it

Compares two configs over the same snapshot: candidates added, removed, rescored or blocked, drift and lifecycle changes, proposals that would re-plan. Tune thresholds with evidence instead of vibes.

ion pause

The kill switch

Creates ~/.ion/PAUSED. Every executor and tracker write stops until ion resume. Reads, grep and reports keep working, so you can investigate with the machine’s hands visibly off the controls.

G4 // Scheduling it, then phase 2Phase 1Phase 2 planned

Daily is enough. Dry-run until it has earned more.

Phase 1 is a LaunchAgent on a Mac. The installer renders the job file and deliberately does not load it, so you read it first:

deploy/install.sh ~/.ion/ion.yml
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.aska.ion.plist

It runs ion run daily at 06:30 and logs to ~/.ion/ion.log. The shipped job keeps executors in dry-run. Add --apply only after a few weeks of proposals you would have approved anyway, and keep the source tree outside ~/Documents to avoid macOS privacy prompts. Any scheduler that can run one command a day works as well.

Phase 2, when cost or uptime justify it, swaps the laptop for a GitHub App identity and a scheduled GitHub Action with llm.backend: anthropic_api. Only config changes. The pipeline, gates and guards do not move.

A sane first month

  1. Week 1: dry runs only. Read every proposal. Tune thresholds with plan-config until the noise is gone.
  2. Week 2: approve two or three small health or policy proposals by hand. Watch explain after each.
  3. Week 3: approve one small merge or autofix. Check the provenance trailers and the tree proof in the pull request.
  4. Week 4: schedule the daily run. Promote at most one policy class to fix. Leave archives manual forever, because ion will.