{"id":48645300,"url":"https://github.com/marcelocantos/bullseye","last_synced_at":"2026-05-17T04:05:48.520Z","repository":{"id":349655964,"uuid":"1203309109","full_name":"marcelocantos/bullseye","owner":"marcelocantos","description":"MCP server for managing targets — desired states with dependency tracking and frontier computation","archived":false,"fork":false,"pushed_at":"2026-05-11T08:15:25.000Z","size":642,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-11T10:26:12.505Z","etag":null,"topics":["convergence","mcp","rust","targets","wsjf"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcelocantos.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-04-06T23:31:52.000Z","updated_at":"2026-05-11T08:15:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/marcelocantos/bullseye","commit_stats":null,"previous_names":["marcelocantos/bullseye"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/marcelocantos/bullseye","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelocantos%2Fbullseye","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelocantos%2Fbullseye/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelocantos%2Fbullseye/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelocantos%2Fbullseye/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcelocantos","download_url":"https://codeload.github.com/marcelocantos/bullseye/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelocantos%2Fbullseye/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33127010,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T18:38:32.183Z","status":"online","status_checked_at":"2026-05-17T02:00:05.366Z","response_time":107,"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":["convergence","mcp","rust","targets","wsjf"],"created_at":"2026-04-10T03:01:21.910Z","updated_at":"2026-05-17T04:05:48.515Z","avatar_url":"https://github.com/marcelocantos.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bullseye\n\nAn MCP server for managing **targets** — desired project states\nexpressed as testable properties, with dependency tracking and\nfrontier computation.\n\nTargets live in `bullseye.yaml` (source of truth). Each repo chooses —\nonce, at `bullseye_init` time — whether its `bullseye.yaml` lives\n**in-repo** (committed alongside the code) or **external** (in a shadow\ntree under `~/.local/share/bullseye/` mirroring the cwd's absolute path).\nDiscovery checks both locations and uses whichever already exists. See\n[Storage locations](#storage-locations) below.\n\n## Installation\n\nRecommended (Homebrew, macOS / Linux):\n\n```bash\nbrew install marcelocantos/tap/bullseye\n```\n\nOr from source:\n\n```bash\ncargo install --path .\n# or\ncargo build --release   # binary at target/release/bullseye\n```\n\nRepository: \u003chttps://github.com/marcelocantos/bullseye\u003e\n\n### Quick start (for an agent)\n\nIf you'd rather have your coding agent set this up, paste the\nfollowing prompt into the agent:\n\n```\nInstall bullseye from https://github.com/marcelocantos/bullseye:\n1. brew install marcelocantos/tap/bullseye\n2. claude mcp add --scope user bullseye -- bullseye\n3. Restart this session (the MCP registration only takes effect on the next session start).\n4. Verify by calling bullseye_startup_context with cwd set to my current project.\n\nThen read https://raw.githubusercontent.com/marcelocantos/bullseye/master/docs/agents-guide.md\nfor the full agent guide.\n```\n\n## MCP client configuration\n\nAdd to `.mcp.json` (project scope) or `~/.claude.json` (user scope):\n\n```json\n{\n  \"mcpServers\": {\n    \"bullseye\": {\n      \"command\": \"bullseye\",\n      \"args\": []\n    }\n  }\n}\n```\n\nOr via the CLI:\n\n```bash\nclaude mcp add --scope user bullseye -- bullseye\n```\n\nThe server communicates over stdio using the MCP protocol.\n\n## Storage locations\n\nEach repo picks its location **once**, when you call `bullseye_init`:\n\n| Location | Where `bullseye.yaml` lives | Use when |\n|----------|-----------------------------|----------|\n| `in_repo` | Inside the repo, discovered by walking up from `cwd`. | You own the repo and the team has adopted bullseye. |\n| `external` | Shadow tree under `~/.local/share/bullseye/` mirroring the cwd's absolute path. Discovery walks up the shadow tree the same way it walks up the real tree. | Repo is read-only to you (corporate repos where bullseye isn't adopted), or targets are personal to you. |\n\nExternal mode is purely path-driven — no assumptions about git remotes\nor `host/org/repo` layouts — so monorepos, non-git directories, and\nunconventional workspaces all resolve identically.\n\n**Discovery is automatic after init.** Every target-operating tool calls\n`discover_anywhere(cwd)`, which checks the in-repo walk-up first and\nthen the shadow walk-up. Whichever file already exists wins. If both\nexist (edge case — e.g. a moved repo), **in-repo wins**: an explicit\ncommitted file is always authoritative.\n\n**No global config file.** Each repo's location is encoded by where\nits `bullseye.yaml` lives on disk. There's nothing to sync across\nmachines, no `~/.config/bullseye/` directory, and no machine-wide\nsetting to get wrong.\n\n## Concurrency protocol\n\n`bullseye.yaml` is expected to be edited by bullseye **and** by humans,\nscripts, and other tools. Every mutating bullseye tool follows this\nprotocol so concurrent writers serialise cleanly and lost-update races\ndon't silently clobber each other:\n\n1. **Out-of-tree lockfile.** Bullseye acquires an exclusive advisory\n   lock (POSIX `flock(2) LOCK_EX`; Windows `LockFileEx`) on a 0-byte\n   sentinel file under `std::env::temp_dir()/bullseye/locks/`, named\n   by the hex `(dev_t, ino_t)` of the yaml's parent directory. Keying\n   on the parent dir's inode pair means the lock follows the project\n   across atomic-rename writes (which change the yaml's inode but not\n   the parent's), repo directory renames (which keep the directory's\n   inode), and symlinked access paths (canonicalised before stat). On\n   macOS this resolves to the per-user `$TMPDIR`; on Linux to `/tmp`.\n   The project directory itself stays clean — no lockfile artefact\n   next to the yaml.\n2. **Bounded wait.** Lock acquisition times out after ~5 s with a\n   structured error naming the contended lockfile. Another tool\n   hanging on the lock does not hang bullseye indefinitely.\n3. **Fresh read.** Inside the lock, bullseye re-reads the yaml from\n   disk, bypassing its in-memory parse cache. Any prior-version state\n   held across tool calls is invalidated.\n4. **CAS on `(mtime, len)`.** Before writing back, bullseye re-stats\n   the yaml. If either field changed between read and write — caught\n   when a non-flock-honouring writer (a text editor, a quick-edit\n   script) modified the file under our nose — the mutation fails with\n   a conflict error and is not applied.\n5. **Atomic write.** The new yaml is written to a sibling tempfile in\n   the same directory, fsync'd, then renamed into place. Readers see\n   either the old or the new file, never a half-written one.\n6. **Lock release on drop.** The flock is released when bullseye's\n   file handle drops at the end of the operation.\n\n**If your tool wants to edit `bullseye.yaml` safely alongside bullseye:**\nthe simplest path is to rely on bullseye's CAS-on-`(mtime, len)`\ndetection — do your read-modify-write quickly; if bullseye's flock\nwindow overlaps yours, its CAS check will detect your edit and\nreport a conflict rather than clobbering it. On conflict, retry. To\nparticipate in bullseye's flock directly, replicate the lock-path\ncomputation: `canonicalize` the yaml's parent directory, take its\n`(dev_t, ino_t)`, and `flock` the file\n`\u003ctemp_dir\u003e/bullseye/locks/\u003cdev\u003e-\u003cino\u003e.lock` (`mkdir -p` the parent\nfirst; the lockfile auto-creates as a 0-byte sentinel).\n\n**First time in a new repo:**\n\n```\n# Pick in-repo (team-adopted repo, committing alongside code):\nbullseye_init location=in_repo\n\n# Or external (read-only / corporate repo, or personal use):\nbullseye_init location=external\n```\n\nAfter that, every other bullseye tool just works.\n\n## Tools\n\nBullseye exposes 16 MCP tools. All target-operating tools accept a\n`cwd` parameter; discovery resolves the targets file automatically.\n\n| Tool | Description |\n|------|-------------|\n| `bullseye_list` | List targets (active/achieved/all) |\n| `bullseye_get` | Get a single target by ID with full detail |\n| `bullseye_put` | Upsert a target — create (auto- or explicit ID) or patch in one call. Rejects content patches on achieved targets unless re-opened in the same call. |\n| `bullseye_retire` | Mark a target achieved |\n| `bullseye_revert` | Move a target from achieved back to converging (e.g. a regression proves the achievement was premature). Clears the achieved date and appends a timestamped revert note to the target's context. |\n| `bullseye_set_aside` | Set a target aside (parked / deferred / wont-fix) with a required rationale. Distinct from retirement: the target was not delivered, but it's removed from the active set and unblocks dependents the same way an achieved target does. |\n| `bullseye_verify` | Emit a structured plan that maps each of a target's `checks` to a sawmill tool invocation. Plan-only — the calling agent runs the checks and folds results back. |\n| `bullseye_frontier` | Unblocked leaf targets ready for work, ordered by maximum unblocking fanout then target ID |\n| `bullseye_validate` | Check schema conformance |\n| `bullseye_graph` | Generate Mermaid dependency graph |\n| `bullseye_import` | Import targets from markdown into YAML |\n| `bullseye_init` | Create starter bullseye.yaml with sample target |\n| `bullseye_startup_context` | Session startup context (frontier, recent achievements, warnings) |\n| `bullseye_portfolio` | Cross-repo portfolio summary with frontier targets, including cross-repo edges |\n| `bullseye_summary` | Consolidated status overview: groups, frontier ordered by unblocking fanout, blocked, stale |\n| `bullseye_convergence` | End-to-end convergence evaluation: runs `make bullseye` for invariants, scans git for unreleased fixes, emits summary with frontier detail inline, and computes a deterministic next-action recommendation. Single call, replaces the old multi-tool `/cv` worker. |\n\nSee [agents-guide.md](docs/agents-guide.md) for detailed tool\nparameters, the bullseye.yaml schema, usage workflows, and a\n[copy-pasteable CLAUDE.md snippet](docs/agents-guide.md#agent-integration)\nfor wiring Bullseye into your project's agent instructions.\n\n## CLI subcommands\n\nBeyond the MCP server, bullseye exposes a small CLI for cron-driven\nmaintenance:\n\n| Subcommand | Purpose |\n|------------|---------|\n| `bullseye sync-priorities` | Scan the workspace, compute the portfolio frontier, and upsert each frontier target into a SQLite `targets_priorities` table. Designed for periodic invocation from cron or a daemon hook. See [mcp-triad.md §7](docs/mcp-triad.md) for the Protocol-app sync chain. |\n\nExample crontab entry (every 30 minutes):\n\n```\n*/30 * * * * /usr/local/bin/bullseye sync-priorities\n```\n\nRun `bullseye sync-priorities --help` for flags (`--db`, `--root`,\n`--horizon`, `--max-depth`).\n\n## Key concepts\n\n- **Frontier**: The set of unblocked leaf targets that can be worked\n  on right now, in parallel. The frontier is the *parallelisable set*\n  — agents are expected to fan out across it rather than pick a single\n  item at a time.\n- **Frontier ordering**: Within a repo, frontier targets are ordered\n  by descending unblocking fanout (count of active targets that depend\n  on this one), tiebroken by ascending target ID. Per-target\n  `value`/`cost` are not consumed by repo-level ordering — those are\n  portfolio-scope inputs only.\n- **Phase boundary**: Bullseye uses different prioritisation engines\n  at repo and portfolio scopes. Inside a repo (sub-week horizon,\n  human as decision-maker), ordering is driven by unblocking fanout.\n  Across repos (weekly-plus horizon, human as bottleneck allocator),\n  WSJF with momentum and cross-repo enabler propagation earns its\n  keep. See `docs/mcp-triad.md` §9.\n- **Verification**: The acceptance criteria on every target *are* the\n  verification contract. Whether the pass signal comes from CI, a\n  human review, a smoke test, or a design walkthrough is free text on\n  the acceptance field — not a property of the node type. Every target\n  is structurally identical; there is no separate \"verify-kind\".\n\n## Development\n\n```bash\ncargo build          # Build\ncargo test           # Run unit + integration tests\ncargo clippy         # Lint\ncargo fmt --check    # Check formatting\n```\n\nSee [CLAUDE.md](CLAUDE.md) for architecture details.\n\n## License\n\nApache 2.0 — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcelocantos%2Fbullseye","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcelocantos%2Fbullseye","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcelocantos%2Fbullseye/lists"}