{"id":51403528,"url":"https://github.com/jamesaphoenix/trail","last_synced_at":"2026-07-04T09:03:51.467Z","repository":{"id":366344373,"uuid":"1275927862","full_name":"jamesaphoenix/trail","owner":"jamesaphoenix","description":"A tiny coverage scheduler with memory for AI agent loops: hands an agent the next folder to cover, per task-name.","archived":false,"fork":false,"pushed_at":"2026-06-21T11:56:24.000Z","size":110,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-21T12:22:17.041Z","etag":null,"topics":["agentic","ai-agents","cli","code-review","coverage","rust","sqlite"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesaphoenix.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-21T10:17:39.000Z","updated_at":"2026-06-21T11:56:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jamesaphoenix/trail","commit_stats":null,"previous_names":["jamesaphoenix/trail"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jamesaphoenix/trail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesaphoenix%2Ftrail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesaphoenix%2Ftrail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesaphoenix%2Ftrail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesaphoenix%2Ftrail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesaphoenix","download_url":"https://codeload.github.com/jamesaphoenix/trail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesaphoenix%2Ftrail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35115745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic","ai-agents","cli","code-review","coverage","rust","sqlite"],"created_at":"2026-07-04T09:03:50.848Z","updated_at":"2026-07-04T09:03:51.455Z","avatar_url":"https://github.com/jamesaphoenix.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# trail\n\nA tiny coverage scheduler with memory, for AI coding agents running in loops.\n\n`trail` hands an agent the next **folder** to work on for a named **task**,\nleases it so parallel agents never collide, records the visit, and uses that\nhistory to order future work. It replaces hand-written \"go look for P0/P1/P2\nbugs in feature X\" JSON files that stop scaling as a codebase grows.\n\n\u003e Name note: `trail` is a working name (the tool leaves a trail of where agents\n\u003e have been). Rename later via the workspace package if you like.\n\n## Why\n\nWhen you run a Ralph-style loop that spawns a fresh agent each iteration, the\nagents have no shared memory of where prior iterations already looked, so they\ncollide or re-tread the same folders. `trail` owns that coverage state as a\nsingle small SQLite file and exposes it through a CLI (plus thin Python/Node\nwrappers), so any harness that can run a shell command can coordinate cleanly.\n\n## Model\n\n- **Folder** is the unit of work.\n- A **sweep** is one-pass coverage: each folder is handed out exactly once, then\n  the sweep is complete. The outer loop owns starting the next sweep.\n- **Memory is per task-name and persists across sweeps.** When a sweep opens,\n  each folder's priority is frozen from staleness (time since it was last\n  visited under this task) plus a static weight (file count / size / churn). If\n  a sweep is cut short, the stalest and heaviest folders were surfaced first.\n- **Strategies** only reorder the one-pass drain: `weighted` (default),\n  `round-robin` (pure least-recently-visited), `random` (seeded, reproducible).\n- **Outcome feedback** (opt-in via `strategy.outcome_weight`): agents report\n  findings with `done --found N` / `--clean`, and folders that recently found\n  more are surfaced earlier in future sweeps. Off by default.\n- **Leases** make parallel work safe: a claimed folder is held for a TTL; if the\n  agent dies the lease expires and the folder returns to the pool, so a sweep\n  completes only when every folder is genuinely covered.\n\n## Build / install\n\n```bash\ncargo build --release          # binary at target/release/trail\n\n# install the `trail` binary onto your PATH:\ncargo install --path crates/trail-cli\n# (the crate is `trail-cli` but its [[bin]] is named `trail`, so the installed\n#  command is `trail`.)\n\n# optional: enable the git-churn static signal (needs cmake for vendored libgit2)\ncargo build --release --features churn\n```\n\nThe language wrappers locate the binary via `PATH`, or via the `TRAIL_BIN`\nenvironment variable (e.g. `TRAIL_BIN=/path/to/trail`).\n\nTagged releases (`v*`) build prebuilt binaries for Linux, macOS (Intel + Apple\nSilicon), and Windows via GitHub Actions.\n\nShell completions:\n\n```bash\ntrail completions zsh  \u003e ~/.zfunc/_trail      # or bash / fish / powershell / elvish\n```\n\n## Use\n\n```bash\ntrail init                              # scan the tree, register folders\ntrail next --task refine --agent a1     # claim a folder (JSON on stdout)\ntrail done --task refine --path src/api --agent a1\ntrail status --task refine\n```\n\n`trail init` also writes a sample `.trail.toml.example` when none exists (the\n`wrote_example_config` field reports whether it did).\n\nExit codes carry the loop outcome: `0` ok, `3` sweep-complete, `4`\nnone-available (leased elsewhere, retry), `1` error, `2` usage. See\n[`skills/trail/SKILL.md`](skills/trail/SKILL.md) for the full command reference\nand the correct parallel-safe loop.\n\n## Config (`.trail.toml`)\n\nCommit `.trail.toml`; gitignore `.trail/` (the state DB). `.gitignore`/`.ignore`\nand hidden dirs are excluded for free; config only layers extra globs. See\n[`.trail.toml.example`](.trail.toml.example).\n\n## Wrappers and bindings\n\nThin wrappers (shell out to the binary, parse JSON):\n\n- Python: [`wrappers/python`](wrappers/python)\n- TypeScript / Node: [`wrappers/typescript`](wrappers/typescript)\n- Go: [`wrappers/go`](wrappers/go)\n- Ruby: [`wrappers/ruby`](wrappers/ruby)\n\nNative, in-process bindings (no subprocess; same shapes as the CLI):\n\n- Python via pyo3: [`bindings/python`](bindings/python)\n- Node via napi-rs: [`bindings/node`](bindings/node)\n\nThe shell-out + JSON + exit-code contract makes a thin wrapper in any language\ntrivial; the native bindings run the scheduler directly for hot loops.\n\n## Layout\n\n```\ncrates/trail-core   library: walk, scoring, SQLite store + atomic claim/lease\ncrates/trail-cli    the `trail` binary\nwrappers/           thin Python + TypeScript wrappers (shell out)\nbindings/           native in-process bindings (pyo3 Python, napi-rs Node)\nskills/trail        SKILL.md for agents\n```\n\n## Performance\n\nState lives in one SQLite file and the hot path is built to stay flat as a\ncodebase grows: `claim`, `complete`, and `status` are O(1) (per-sweep counters,\nnot `COUNT(*)` scans), and SQL is compiled once per process (`prepare_cached`).\nDraining a 50k-folder sweep takes ~1.1s (~22us per claim+complete cycle, flat\nfrom 1k to 50k folders). Run the micro-benchmark with:\n\n```bash\ncargo run --release --example bench -p trail-core\n```\n\nFor tight loops, the native [`bindings/`](bindings) avoid per-call process\nspawn entirely. If counters ever drift, `trail gc --reconcile` rebuilds them.\n\n## Test\n\n```bash\ncargo test          # unit, scoring, lifecycle, concurrency, CLI e2e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesaphoenix%2Ftrail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesaphoenix%2Ftrail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesaphoenix%2Ftrail/lists"}