GoRefactor is a deterministic, AST-aware command-line tool for analyzing and refactoring Go code. It's designed for safe, repeatable structural edits that won't silently break your code.
Key innovations:
- Semantic targeting: Refactoring operations use function names, code patterns, and variable analysis instead of fragile line numbers—your plans stay valid even when code evolves
- Harness pattern: Operations refuse to produce malformed Go (AST-aware, with goimports built-in), so the failure mode is “command rejects” not “file silently breaks”
- LLM-integrated: Companion binary
gorefactor-agentenables iterative or autonomous refactors with Claude, GPT, or local LLMs—the LLM proposes operations, the tool executes them deterministically - Batch refactoring: JSON orchestration plans let you specify 10 similar edits once and apply them everywhere
See CLAUDE.md for agent modes, developer workflow, and architectural patterns.
| Binary | Role |
|---|---|
gorefactor |
Deterministic CLI: analysis, direct edits, lint, plans, undo |
gorefactor-agent |
LLM loop that calls gorefactor; never edits .go files directly |
# Pin to a release (recommended)
go install github.com/chrisophus/gorefactor/cmd/gorefactor@v0.13.0
go install github.com/chrisophus/gorefactor/cmd/gorefactor-agent@v0.13.0
# Or latest from main
go install github.com/chrisophus/gorefactor/cmd/gorefactor@latest
go install github.com/chrisophus/gorefactor/cmd/gorefactor-agent@latestOr use prebuilt binaries from Releases.
- Operations refuse to produce malformed code (AST-aware, runs goimports, validates before writing)
- Failure mode: "command rejects the change" not "silently broken file"
- Compare to:
sedscripts (can silently break) or manual edits (typos, missed imports)
Refactoring plans use semantic targeting, not line numbers:
{
"type": "extract_method",
"target": {
"functionName": "ProcessPayment",
"variableNames": ["card", "amount"],
"codePattern": "if.*checksum"
}
}Even if someone adds 10 lines above the extraction block, the plan still works. With line numbers, it would be off by 10.
The agent (gorefactor-agent) never directly edits .go files—it proposes operations and calls gorefactor deterministically. This means:
- No prompt injection: LLM can't accidentally write malformed code
- Cheap: Uses local or cheap LLMs (qwen 14b: 80% success rate on complex refactors)
- Auditable: Every change is a gorefactor command, not opaque LLM-generated code
- Recoverable: Built-in
undorolls back snapshots
Apply the same refactoring to 10 files in one operation:
# One JSON plan, all files
gorefactor orchestrate consolidate-error-handling.json
# vs. manual: repeat the same change 10 times, pray for consistencygorefactor lint . # Detect structural issues
gorefactor lint . --fix # Auto-fix what's safe (split files, remove dead code, wrap errors, drop redundant logs)
gorefactor lint . --fix --verify # ...and revert any fix that breaks `go build`/`go test`
gorefactor lint . --fix --verify --fix-level aggressive # also shorten long functions, lift return-bearing blocks, delete module-wide dead exported funcs, fix non-adjacent log/return
gorefactor lint . --fail-only # Show only blocking (error-severity) issues
gorefactor doctor # Lint + golangci-lint + build + test (final gate)Rule tiers (set in .gorefactor.yaml under rules:):
| Tier | Role |
|---|---|
error |
Deterministic CI gate (--fail-on error, default) |
warning |
Actionable debt; normally held by a committed baseline ratchet (baseline.enabled: true, --fail-on warning) |
info |
Opt-in exploration (--info; hidden by default) |
off |
Rule disabled |
With --quiet --fail-only, lint exits silently when nothing reaches --fail-on — warnings and info below the gate are intentionally hidden.
Focused policy config (optional YAML blocks):
tracked_artifact:
allow_extensions: [.png, .ico, .tgz]
allow_path_prefixes: [docs/assets/, ui/vendor/]
lint:
exclude_test_files: [error-not-wrapped]
exclude_packages:
high-coupling: [internal/domain, internal/wire]
thresholds:
high-coupling:
fan_in: 12
fan_out: 15
baseline:
enabled: true
file: .gorefactor-lint-baseline.jsonCLI baseline flags override YAML (--baseline, --no-baseline, --baseline-file). A future generalized per-rule policy DSL is deferred until multiple consumers need it — see docs/project-review-2026-07-19.md (P4).
The default rule set has 48 rules, grouped by concern (canonical list in cmd/gorefactor/lint_registry_test.go):
- Size & structure:
file-size(>500 lines, split hints by receiver/prefix),hard-to-maintain(long and complex/nested/error-dense — allows long-but-simple orchestrators),long-function/deep-nesting/complexity(single-axis info sensors),extract-candidate - Duplication:
duplicate-block(>100-line clones with consolidation hints),duplicate-bare-sentinel - Design smells:
god-object,large-class,fat-interface,excessive-params,excessive-returns,data-clumps,type-switch,premature-abstraction,high-coupling - Error handling:
error-not-wrapped(barereturn err),if-err-log-return,wrap-log-return,wrap-bridge-log-return,redundant-nil-guard(unexported entry nil-checks already proven by all in-package callers),unnecessary-nil-check(checks provably excessive within one function: freshly constructed values, duplicate guards, checks inside a!= nilbranch,x != nil && len(x) > 0) - Ordering:
funcorder-constructor(constructor must follow the struct, before its methods),funcorder-struct-method(exported methods before unexported),funcorder-function(exported top-level functions before unexported ones, excluding constructors andinit()) — ports golangci-lint'sfuncorderdefault checks plus its opt-infunctioncheck - Coverage:
untested-function,untested-package - Test hygiene:
vacuous-test,sleep-in-test - Libraries / lifecycle / concurrency:
fatal-in-library,unstopped-ticker,naked-goroutine,pass-through-param - Performance:
regexp-compile-in-func,string-concat-in-loop,linear-search-in-loop - Dead code:
dead-code(unused funcs/types across the module) - Impact / self-audit:
high-blast-radius,low-gorefactor-adherence - Harness residue:
generated-name,byvalue-buffer,stranded-comment(covers both mis-attached doc comments and free-floating narration),orphaned-config-path,tracked-artifact(git-tracked binaries/coverage reports) Bothgo-arch-lintandgolangci-lintare deliberately kept out of thelintrule set —doctorruns each as its own stage (both self-skip when the binary or config is absent), keepinglintfast and fully in-process. Run them independently withgo-arch-lint check/golangci-lint run, or together viagorefactor doctor.
--fix autofixes the rules with a single safe transformation: file-size (via split), dead-code (delete unreferenced decls), error-not-wrapped (wrap with fmt.Errorf(... %w)), the log-propagation rules (via remove-log-return — delete the redundant log next to a propagating return, wrap a bare return err), duplicate-bare-sentinel (via wrap-sentinels), and funcorder-constructor/funcorder-struct-method/funcorder-function (via reorder-funcorder). Add --verify to make each fix self-checking: fixes are applied in batches of up to 8 (defaultAutoFixBatchSize), each batch is gated by go build ./... + go test ./..., and a failing batch is bisected so only the offending fix is reverted while the rest are kept — so bulk --fix is safe to run unsupervised even where a sensor over-approximates.
vs. alternatives:
- gopls: Great for interactive refactoring in an IDE, slow for CLI (60× slower cold-start)
- go/analysis: Low-level; you write the analysis rules yourself
- golangci-lint: Linting only; no refactoring or suggestions
- Manual scripts: Fragile (line numbers, imports), easy to break
Campaign mode drives autonomous cleanup from lint findings; the default agentic mode is a tool-calling loop gated by go build + go test. For well-scoped structural tasks, prefer the direct CLI (see benchmark/FINDINGS.md).
Build from source:
make build # gorefactor (runs test, lint, vet first)
go build -o gorefactor-agent ./cmd/gorefactor-agent| Scenario | GoRefactor | Manual edit | gopls/IDE |
|---|---|---|---|
| Extract a 20-line method | ✅ Auto-infer params/returns | Need to count locals | Works but slower |
| Rename across 5 files | ✅ Semantic (handles shadowing) | Error-prone | Works, but requires IDE |
| Move function to new file | ✅ Auto-handle imports | Manual import edits | Works |
| Split a 500-line file | ✅ Auto-suggest by complexity/receiver | Not practical | N/A |
| Find dead code | ✅ Cross-file analysis | Guess/search | Limited |
| Fix 20 files (same pattern) | ✅ JSON plan, one execution | Repeat 20 times | Not applicable |
| Refactor driven by LLM | ✅ Agent calls gorefactor | Agent must edit directly | Not applicable |
| Bottom line | Safe, repeatable, fast | Error-prone | Interactive only |
Best fit: Large refactors, automated cleanup in CI, LLM-driven changes, or teams applying consistent patterns across multiple files.
# Structural issues in the module
./bin/gorefactor lint .
# Autofix oversized files where safe
./bin/gorefactor lint . --fix
# Final gate: full structural lint + golangci + arch + go build + go test
./bin/gorefactor doctor
# One-page summary of a file
./bin/gorefactor inspect path/to/file.go
# Agent: autonomous cleanup from lint findings (needs API key)
./bin/gorefactor-agent -campaignRun ./bin/gorefactor with no subcommand arguments to print the full command list.
Every command that accepts --json emits one shared envelope — {"ok": bool, "error": "...", "data": {...}} — with the command-specific payload under
data. Machine consumers can branch on ok without knowing per-command
shapes (pinned by TestEnvelopeContractIsUniversal).
| Command | Purpose |
|---|---|
parse |
File structure as JSON |
list-functions |
Functions/methods with line counts |
recommend |
Ranked extraction candidates |
inspect |
Human-readable file summary + lint hints |
find-callers |
Who calls a function or Receiver:Method |
find-uses |
References to a symbol |
find-implementations |
Types implementing an interface |
find-package-deps |
Package dependency graph + circular-import detection |
analyze-diff |
Refactoring plan from a patch file |
analyze-file-sizes |
Oversized files and split hints |
suggest-plan |
Suggested refactoring plan for a file |
callgraph |
Transitive call tree (callees, or --callers) for a function/method |
context |
One-shot LLM context pack for a symbol: def, callers, signature types, tests (--budget N) |
skeleton |
File with function bodies elided — token-cheap file shape |
search-ast |
Structural search; match a statement/expression pattern ($_ wildcard) |
api-diff |
Diff the exported API surface vs a git ref (default HEAD) |
review |
Structural quality review of changed functions vs a git ref |
test-affected |
Map changed files to transitively affected packages and their tests (--run) |
architect |
Generate a starter go-arch-lint.yml from the import graph |
history |
List the journal of mutation operations |
Methods use Receiver:Method (no * on the receiver). Many commands accept - as the last argument to read body content from stdin.
| Command | Purpose |
|---|---|
create |
New .go file |
insert |
Code at at-end, after:Func, inside:Func, etc. |
replace |
AST statement replace inside a function |
replace-text |
Literal text replace inside a function |
replace-body |
Replace a function/method body wholesale |
delete |
Remove a declaration (--safe checks callers first) |
rename |
Unexported symbol, package-wide |
move |
Move declaration to another file |
extract |
Extract line range to new function |
extract-var |
Bind an expression to a new local variable and rewrite occurrence(s) |
extract-const |
Like extract-var but emits a local const |
inline |
Inline a simple function into call sites and delete it |
add-field |
Add a struct field; optionally rewrite positional literals to keyed |
change-signature |
Add/remove/rename a parameter and update all call sites |
change-receiver |
Switch a method receiver between value and pointer form |
set-doc |
Set/replace the doc comment on a declaration |
insert-switch-case |
Add a case to the switch inside a function |
insert-map-entry |
Append an element to a map/slice composite literal |
replace-in-literal |
Replace text inside one string literal (AST-scoped; use -- for dash-leading args) |
add-test |
Generate a table-driven test scaffold for a function/method |
extract-interface |
Generate an interface from a type's exported method set |
implement-interface |
Generate compiling method stubs for unimplemented interface methods |
wrap-errors |
Rewrite bare return err in if err != nil blocks to fmt.Errorf wrapping |
hoist-regexp |
Hoist function-local constant regexp.MustCompile calls to package level |
split |
Auto-split an oversized file |
format |
gofmt + goimports in place |
| Command | Purpose |
|---|---|
lint |
48 structural rules (size, duplication, smells, error handling, ordering, coverage, dead-code, arch); skips vendor/.git/node_modules and *.gen.go/_gen.go. --fix autofixes file-size, dead-code, error-not-wrapped, complexity, the log-propagation family, funcorder-constructor/funcorder-struct-method/funcorder-function (via reorder-funcorder) (add --verify to revert any fix that breaks build/test). --fix-level aggressive (requires --fix --verify) additionally autofixes long-function/extract-candidate by extraction, lifts return-bearing blocks, fixes non-adjacent log/return pairs, and deletes module-wide unreferenced exported functions. --fail-only shows blocking issues only |
doctor |
Gate: full structural lint registry + golangci-lint + go-arch-lint + go build + go test; non-zero on failure. --report merges substrates into one advisory report (optional --score) |
adherence |
Harness self-audit: fraction of changed .go files edited via gorefactor vs raw Write/Edit |
intent |
Declare a deliberate exported-API change so the apidiff gate passes it |
txn |
Apply a batch of mutation commands transactionally (all-or-nothing, single undo unit) |
undo |
Undo the most recent journaled mutation (or restore a named plan snapshot) |
init-agent-rules |
Write the agent-rules snippet into CLAUDE.md / .cursorrules / AGENTS.md; --mcp also emits a .mcp.json pointing a client at gorefactor mcp |
mcp |
Run a stdio MCP server exposing gorefactor's tools to any MCP client (see below) |
| Command | Purpose |
|---|---|
orchestrate |
Run a refactoring plan file |
exec |
Single operation from JSON/stdin |
generate-templates |
Example plan templates |
repl |
Interactive step-by-step refactoring |
Details and JSON plan schema: ORCHESTRATION_SYSTEM.md, orchestrator/README.md.
gorefactor mcp runs a stdio Model Context Protocol
server (built on the official Go SDK) so any MCP client — Claude Code, Cursor,
Copilot — gets gorefactor's exact, AST/type-based Go intelligence as native
tools. Unlike embedding-based indexers it's exact for Go and it can edit.
# Point the current project's client config at the server
gorefactor init-agent-rules --mcp # writes/merges .mcp.json
# Read-only by default: parse, skeleton, callgraph, blast-radius,
# find-callers/uses, search-ast, lint, ... plus skeleton/inspect/context
# served as MCP resources (gorefactor://skeleton/<path>, etc.)
gorefactor mcp
# Opt in to the safe-edit guides (create/insert/replace/move/rename/delete/txn/undo)
# as destructive-annotated tools. Requires a clean git worktree so every edit is
# reversible with `git reset --hard` (pass --allow-dirty to skip that check).
gorefactor mcp --allow-writeDesign and phase status: docs/mcp-server-plan.md.
GoRefactor is project-agnostic — install it once, then wire it into any Go
module. The generated config references gorefactor on your PATH (no hardcoded
paths), so the same setup works everywhere.
# 1. Install binaries + helper scripts globally (from a clone of this repo)
make install
# → gorefactor, gorefactor-agent, gorefactor-delegate, gorefactor-init-project
# installed to $(go env GOPATH)/bin
# 2. In any other Go project, wire in rules + MCP + a commit-time gate
cd ~/my-other-project
gorefactor-init-project # read-only MCP (analysis tools; edits via CLI/rules)
gorefactor-init-project --write # also expose the mutation tools over MCPgorefactor-init-project writes:
- Agent rules —
CLAUDE.md/.cursorrules/AGENTS.md, so Claude Code, Cursor, and AGENTS.md-based agents prefer gorefactor over hand-editing.go. - MCP config —
.mcp.json(Claude Code) and.cursor/mcp.json(Cursor). - Doctor gate — a
.githooks/pre-commitrunninggorefactor doctor(lint + build + test) pluscore.hooksPath. The safety net: broken Go is caught before commit no matter which tool made the edit. Bypass one commit withgit commit --no-verify.
Installed only the binaries (via go install …@latest)? Use the built-ins directly —
gorefactor init-agent-rules --target all --mcp writes the rules + .mcp.json, and any
pre-commit hook that runs gorefactor doctor gives you the gate.
Batch / headless refactors. For large or autonomous mechanical work, delegate a spec to the agent — it runs the cheap model first and escalates only if it hands the task back:
gorefactor-delegate "add a ctx context.Context first param to Foo and update callers"
# → runs on Haiku; on a punt (exit 3) escalates to Sonnet.
# Needs ANTHROPIC_API_KEY and a clean git worktree (rolls back to it on punt).Commands use semantic exit codes so agents and CI can branch on the failure mode:
| Code | Meaning |
|---|---|
0 |
success |
1 |
usage / argument error |
2 |
target or pattern not found (semantic miss — retry with a different target) |
3 |
parse / syntax rejection (snippet or file does not parse) |
4 |
gate failure (go build/go test failed; used by doctor and --gate) |
Most mutation commands also accept --dry-run (preview without writing) and --gate (run build+test after the change, fail with code 4 if broken).
- gopls: Great for interactive IDE refactoring (rename, extract, inline)
- GoRefactor: CLI-based, batch operations, LLM-integrated, resilient to code changes
- Speed: gopls cold-start = ~1.91s; gorefactor = ~30ms (60× faster for CLI bulk ops)
- When to use gopls: Single file, interactive in-editor refactoring
- When to use GoRefactor: Bulk refactoring, CI automation, LLM-driven changes, batch operations
- golangci-lint: Comprehensive linting (security, style, complexity)
- GoRefactor: Structural refactoring + linting with autofixes
- Overlap: Both detect complexity, duplication, dead code
- When to use golangci-lint: Strict linting rules, security scanning, code style enforcement
- When to use GoRefactor: You want autofix + refactoring recommendations in one tool
- go/analysis: Ultra-flexible low-level framework (gopls, golangci-lint plugins use this)
- GoRefactor: High-level, out-of-the-box commands, no DSL to learn
- When to use go/analysis: Custom analysis rules, plugin architecture
- When to use GoRefactor: Pre-built refactoring tools, quick CLI automation
- Manual: Flexible, but error-prone (missed imports, typos, line-number drift)
- GoRefactor: Safe-by-design (AST-aware, runs goimports, validates syntax)
- Cost: GoRefactor = 5 minutes to learn + 30 seconds to run; Manual = 30 minutes to get right + high error rate
- When to use manual: One-off 2-3 line change
- When to use GoRefactor: Anything more complex or repetitive
- IDE: Great UX, interactive, mouse-driven
- GoRefactor: Scriptable, batch-capable, CI/CD integration, LLM-driven
- When to use IDE: Interactive refactoring, small changes, learning
- When to use GoRefactor: Large batch refactors, CI pipelines, LLM agents, complex patterns
gorefactor extract payment.go 23 31 validateCardNumberBefore:
func ProcessPayment(card *Card) error {
// ... setup code ...
// Lines 23-31: Validate card
if len(card.Number) < 13 {
return fmt.Errorf("invalid card number")
}
sum := 0
for _, digit := range card.Number {
sum += int(digit - '0')
}
if sum%10 != 0 {
return fmt.Errorf("checksum failed")
}
// ... rest of function ...
}After: Parameters (card) and returns (error) are automatically inferred:
func validateCardNumber(card *Card) error {
if len(card.Number) < 13 {
return fmt.Errorf("invalid card number")
}
sum := 0
for _, digit := range card.Number {
sum += int(digit - '0')
}
if sum%10 != 0 {
return fmt.Errorf("checksum failed")
}
return nil
}
func ProcessPayment(card *Card) error {
if err := validateCardNumber(card); err != nil {
return err
}
// ... rest ...
}# See what's worth extracting
$ gorefactor recommend payment.go
[
{
"file": "payment.go",
"functionName": "ProcessPayment",
"blockStart": 23,
"blockEnd": 38,
"complexity": 8,
"statementCount": 12,
"reason": "High complexity, good extraction candidate"
},
// ... more recommendations
]
# See which files are oversized
$ gorefactor analyze-file-sizes .
Large files (>500 lines):
handlers.go (687 lines) — suggest splitting by receiver: Handler, Router, Middleware
service.go (612 lines) — suggest splitting by prefix: Payment*, Auth*, Cache*
# Auto-fix
$ gorefactor lint . --fix
Splitting handlers.go into handlers_handler.go, handlers_router.go, handlers_middleware.go
✓ handlers.go
✓ service.goExtract the same validation pattern from 5 different places:
# Generate a plan
$ gorefactor suggest-plan payment.go --patterns > refactor-plan.json
# Review and execute
$ gorefactor orchestrate refactor-plan.json
Applied 5 operations in 1.2s
Refactor committed to .gorefactor/snapshot-20260524-151030 (use 'undo' to rollback)# Find all issues and let the agent fix them
$ gorefactor-agent -campaign -max-iter 10
Step 1/5: Detected file-size violations in handlers.go
→ Splitting into 3 files...
Step 2/5: Found 2 duplicate blocks in service.go
→ Extracted to shared helper...
Step 3/5: Identified untested functions in middleware.go
→ Marked with t.Skip() for visibility...
✓ All issues fixed. Changes committed.# Who calls this function? (helps plan renames/moves)
$ gorefactor find-callers ProcessPayment
handlers/payment.go:45 - ServeHTTP calls ProcessPayment
service/payment.go:12 - authorizeTransaction calls ProcessPayment
agent/payment_test.go:89 - TestPaymentFlow calls ProcessPayment
# Safe to rename/move? Check the 3 call sites.Requires OPENAI_API_KEY or ANTHROPIC_API_KEY (or a local OpenAI-compatible endpoint via -api-base). Tool-calling providers only.
| Mode | Flag | Use when |
|---|---|---|
| Agentic (default) | -spec "..." |
Open-ended refactors; tool loop, up to 40 iterations by default |
| Campaign | -campaign |
Fix gorefactor lint findings autonomously |
-max-iter overrides the mode default (40 for agentic). The agent’s finish gate runs go build + go test only. For lint + build + test, run gorefactor doctor yourself or in CI.
Before reaching for the agent, read benchmark/FINDINGS.md — for well-scoped structural tasks the direct CLI is strictly cheaper (~0 tokens vs 20–75K per task).
GoRefactor follows the harness pattern (Fowler): guides (feedforward—refuse to produce bad code) and sensors (feedback—lint rules with autofixes).
| Package | Responsibility |
|---|---|
| parser/ | AST parsing → structured JSON (package info, functions, methods, types, interfaces). Foundation for all analysis. |
| analyzer/ | Complexity scoring, extraction recommendations, dead code, duplicates, diff analysis, call graphs. Powers recommend, inspect, lint heuristics. |
| orchestrator/ | JSON plan execution, semantic targeting (function names + code patterns + variable usage), undo snapshots under .gorefactor/. Enables resilient batch refactoring. |
| cmd/gorefactor/ | CLI commands. 25+ cmd_*.go files (one per command). Extraction logic in cmd_extract.go (type-aware via go/packages). Direct-mutation commands here (create, insert, replace, delete, move, rename, extract, split, format). |
| cmd/gorefactor-agent/ | LLM harness. Proposes operations (never edits .go directly). Supports OpenAI-compatible and Anthropic providers. Modes: agentic (40-step tool loop) and campaign (autonomous). Completion gate: go build + go test (not lint). |
Design principle: Use GoRefactor when the tool determines where and how; use Claude/LLM when it determines what to change. This minimizes token cost and keeps safety high (deterministic execution, not code generation).
Extract a 200-line function:
- Gorefactor path: LLM identifies the block (50 tokens) → tool extracts, infers params/returns (instant) = 99.5% token savings
- Manual edit path: LLM reads file, outputs new function, new call site (1000+ tokens)
Batch refactoring (apply 1 pattern to 10 files):
- Gorefactor path: One plan (100 tokens) → tool applies 10 times (instant) = 80%+ savings
- Manual path: Repeat the change 10 times in LLM output (1000+ tokens)
See CLAUDE.md → Token Efficiency for the decision matrix.
Quality gates:
make check # fmt, vet, golangci-lint, test (full pre-commit)
make test # tests with race + coverage
./bin/gorefactor doctor # lint + go build + go test (final gate before shipping)
./bin/gorefactor lint . # Check for structural issues (file-size, duplicates, complexity, coupling, etc.)Contributor workflow:
- Use
gorefactorfor.gofile mutations (not Write/Edit). Ensures AST-aware changes and type safety. - Pre-commit hook (optional):
ln -s ../../.githooks/pre-commit .git/hooks/pre-commit - See CLAUDE.md for full developer guidance, harness patterns, and semantic targeting strategy.
Reliability & benchmarks:
- Second-tier agent (qwen2.5-coder 14b) achieves 80% success rate on complex refactoring tasks
- 20% clean punts (warm report, warm handoff to human—not errors)
- Mean time per task: 7 seconds
- Zero frontier tokens (all work is local; frontier spend only for unresolved hand-offs)
- See benchmark/FINDINGS.md for measured token economics and reliability findings.
MIT License