{"id":51033694,"url":"https://github.com/launchapp-dev/animus-subject-requirements","last_synced_at":"2026-06-22T03:01:48.557Z","repository":{"id":359652829,"uuid":"1242730741","full_name":"launchapp-dev/animus-subject-requirements","owner":"launchapp-dev","description":"Requirements subject backend plugin for Animus","archived":false,"fork":false,"pushed_at":"2026-05-22T20:18:28.000Z","size":31,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T22:27:39.872Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/launchapp-dev/animus-cli","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/launchapp-dev.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-05-18T17:44:01.000Z","updated_at":"2026-05-22T19:16:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/launchapp-dev/animus-subject-requirements","commit_stats":null,"previous_names":["launchapp-dev/animus-subject-requirements"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/launchapp-dev/animus-subject-requirements","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/launchapp-dev%2Fanimus-subject-requirements","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/launchapp-dev%2Fanimus-subject-requirements/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/launchapp-dev%2Fanimus-subject-requirements/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/launchapp-dev%2Fanimus-subject-requirements/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/launchapp-dev","download_url":"https://codeload.github.com/launchapp-dev/animus-subject-requirements/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/launchapp-dev%2Fanimus-subject-requirements/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34632723,"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-06-22T02:00:06.391Z","response_time":106,"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":[],"created_at":"2026-06-22T03:01:47.665Z","updated_at":"2026-06-22T03:01:48.541Z","avatar_url":"https://github.com/launchapp-dev.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# animus-subject-requirements\n\nA requirements subject backend plugin for [Animus](https://github.com/launchapp-dev/animus-cli).\n\n\u003e **Status:** Under construction — landing in Animus v0.4.0.\n\n## What this is\n\nAnimus v0.4.0 makes subjects (units of dispatchable work) pluggable. This repository ships `animus-subject-requirements`, a standalone stdio plugin that stores requirements as structured `.md` files on disk and surfaces them as Animus subjects of `kind = \"requirement\"`.\n\nRequirements have a slightly different lifecycle than tasks:\n\n- They go through a **refinement loop** (drafted → refined → approved) before any task is spawned.\n- They typically **outlive the tasks they unlock** — the requirement stays as the durable record long after `TASK-0042` is closed.\n- They cross-reference the tasks and workflows they spawn, so a workflow can dispatch on \"what requirement does this task implement?\"\n\nStoring requirements as files keeps them **git-native**: every refinement is a diff, every approval is a commit, every deprecation is reviewable in a PR.\n\n## Layout\n\n```\n\u003cproject_root\u003e/.animus/requirements/\n├── REQ-0001.md\n├── REQ-0002.md\n├── archived/\n│   └── REQ-0003.md\n└── _index.json\n```\n\nEach `REQ-NNNN.md` file pairs structured YAML frontmatter with a freeform markdown body:\n\n```markdown\n---\nid: requirement:REQ-0001\nkind: requirement\ntitle: \"Users must be able to log in with OAuth\"\nstatus: refined\npriority: high\nlabels: [auth, p1]\nlinked_tasks: [task:TASK-0042, task:TASK-0099]\nlinked_workflows: [delivery]\nacceptance_criteria:\n  - \"Google + GitHub OAuth providers supported\"\n  - \"Session tokens stored server-side, not in localStorage\"\ncreated_at: 2026-05-18T12:00:00Z\nupdated_at: 2026-05-18T13:30:00Z\nrefined_at: 2026-05-18T13:30:00Z\nrefined_by: alice@example.com\ncustom_fields:\n  origin: stakeholder-interview-2026-q2\n---\n\n# REQ-0001: Users must be able to log in with OAuth\n\n## Context\n[Multi-paragraph description...]\n\n## Acceptance criteria\n- [x] Google OAuth provider integrated\n- [ ] GitHub OAuth provider integrated\n```\n\n## Status mapping\n\nRequirements carry a four-state native lifecycle that maps onto Animus's normalized `SubjectStatus` taxonomy:\n\n| Native (`status:`) | Normalized        | Meaning                                        |\n|--------------------|-------------------|------------------------------------------------|\n| `drafted`          | `ready`           | Newly captured; awaiting refinement            |\n| `refined`          | `in-progress`     | Iteratively being clarified                    |\n| `approved`         | `done`            | Approved for downstream dispatch               |\n| `deprecated`       | `cancelled`       | Abandoned without implementation               |\n\nThe native value is surfaced in `Subject.native_status` so workflows can dispatch on the rich vocabulary — e.g. *\"when a requirement moves to `drafted`, run the refinement workflow\"*.\n\n## Why dedicated to requirements?\n\nThis plugin sits beside `animus-subject-markdown` (general task storage in markdown) and `animus-subject-sqlite` (general task storage in SQLite). The split exists because requirements:\n\n- Have an **iterative refine verb** that doesn't exist for tasks.\n- Carry **cross-references to tasks and workflows** as first-class fields.\n- Have **stable IDs that outlive the work** — `REQ-0001` may spawn `TASK-0042`, which closes, but `REQ-0001` stays.\n- Benefit from **git-reviewable mutations** — refining a requirement is exactly the kind of thing you want a PR for.\n\n## Configuration\n\n| Env var                                | Default                                          | Description                                    |\n|----------------------------------------|--------------------------------------------------|------------------------------------------------|\n| `ANIMUS_REQUIREMENTS_ROOT`             | `\u003cproject_root\u003e/.animus/requirements`            | Where requirement files live                   |\n| `ANIMUS_REQUIREMENTS_ID_PREFIX`        | `REQ`                                            | Prefix for new ids (`REQ-0001`)                |\n| `ANIMUS_REQUIREMENTS_INDEX_TTL_SECS`   | `60`                                             | How stale `_index.json` may go before rebuild  |\n| `ANIMUS_REQUIREMENTS_LEGACY_JSON`      | _(unset)_                                        | Path to the in-tree `core-state.json` for legacy read+migrate compat |\n| `ANIMUS_SCOPED_ROOT`                   | _(unset)_                                        | Fallback for legacy path: `\u003cscoped\u003e/core-state.json` is probed when `ANIMUS_REQUIREMENTS_LEGACY_JSON` is unset |\n| `ANIMUS_REQUIREMENTS_MIGRATE_LEGACY`   | `false`                                          | When truthy, runs one-shot legacy → Markdown migration on startup |\n\n## Legacy in-tree JSON compatibility\n\nBefore v0.4.0, requirements lived inside the in-tree `core-state.json` file under `~/.animus/\u003crepo-scope\u003e/`. This plugin can read that legacy file alongside its own Markdown store so existing projects keep working unmodified during the migration:\n\n- **Read+union:** On every `list()` call, legacy entries are merged into the Markdown set. Markdown wins on id collision; legacy entries surface with their rich fields (acceptance criteria, comments, linked tasks, links, legacy id, category, source) preserved under `custom_fields.*` and `custom_fields.origin_store = \"legacy_json\"`.\n- **Read fallback for `get()`:** If a `REQ-NNNN.md` file does not exist, the plugin falls back to the legacy JSON before returning `NotFound`.\n- **Status fold:** The in-tree eleven-state lifecycle (`draft / refined / planned / in-progress / done / po-review / em-review / needs-rework / approved / implemented / deprecated`) collapses to the four-state native model (`drafted / refined / approved / deprecated`). The original string is preserved under `custom_fields.legacy_status`.\n- **One-shot migration:** Set `ANIMUS_REQUIREMENTS_MIGRATE_LEGACY=1` to convert every legacy entry into a `REQ-NNNN.md` file at startup. The legacy `requirements` map is cleared after every entry is successfully written; other top-level fields in `core-state.json` are preserved verbatim. Idempotent — re-running after a successful migration is a no-op.\n\nThe legacy read path is intentionally **append-only on the standalone side**: new requirements always land in Markdown, never back into the legacy JSON. `delete()` on a legacy-only id is a no-op (returns `Ok(false)`) — operators should migrate first, then delete.\n\n### What this plugin does not own (yet)\n\nThe in-tree `BuiltinRequirementsProvider` also exposed three orchestration verbs on the CLI:\n\n- `draft_requirements` — LLM-driven generation of an initial requirement set from project context.\n- `refine_requirements` — LLM-driven iterative clarification of one or more requirements.\n- `execute_requirements` — Materializes approved requirements into tasks via the planning state machine.\n\nThese are **planning-pipeline operations**, not data ops — they require the agent runtime, model registry, and codebase scanner. They do not fit the `SubjectBackend` trait surface (which is data: `list / get / update / watch / health`). The `delete_requirement` CLI verb is implemented locally as [`RequirementsBackend::delete`](src/backend.rs) but is not yet wired through the protocol (the wire `SubjectBackend` trait has no `delete` method as of `animus-subject-protocol` v0.1.6 — adding it is a protocol-version change).\n\nDeleting the in-tree `InTreeRequirementsSubjectBackend` for data ops is unblocked by this release. Removing the three orchestration verbs requires either:\n\n1. Adding a small `subject_planning/*` JSON-RPC namespace to the protocol that orchestrates LLM-driven verbs, or\n2. Keeping those three verbs in the orchestrator-core service layer as a separate (non-subject-backend) facade.\n\n## Index cache\n\nListing requirements walks the entire directory, which is fine for tens but bad for thousands. The plugin maintains `_index.json` — a flat cache of every requirement's frontmatter that is rebuilt when:\n\n1. The cache file is older than `ANIMUS_REQUIREMENTS_INDEX_TTL_SECS` (default 60s).\n2. Any `*.md` file's `mtime` is newer than the cache file's `mtime` (catches external edits like `git pull`).\n\nRebuilds are guarded by an in-process lock so concurrent calls don't all scan.\n\n## Subject schema\n\n```yaml\nkinds: [requirement]\nstatus_values: [ready, in-progress, done, cancelled]\nsupports_create: true\nsupports_watch: true\nsupports_pagination: true\nnative_status_values: [drafted, refined, approved, deprecated]\n```\n\nWatch is implemented via [`notify`](https://crates.io/crates/notify) — every `*.md` change under the requirements root emits a `subject/changed` notification.\n\n## Development\n\n```bash\ncargo build --release\ncargo test\ncargo clippy --all-targets -- -D warnings\ncargo fmt --check\n./target/release/animus-subject-requirements --manifest\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaunchapp-dev%2Fanimus-subject-requirements","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaunchapp-dev%2Fanimus-subject-requirements","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaunchapp-dev%2Fanimus-subject-requirements/lists"}