{"id":48970786,"url":"https://github.com/devonestar/janus","last_synced_at":"2026-04-18T07:03:13.034Z","repository":{"id":351916674,"uuid":"1212367989","full_name":"devonestar/janus","owner":"devonestar","description":"AI-native decision gate for PRD/spec markdown. Reads your plan, finds fragile paths, and blocks them before they become code.","archived":false,"fork":false,"pushed_at":"2026-04-17T02:27:47.000Z","size":136,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-17T04:26:50.204Z","etag":null,"topics":["agent","ai","claude","cli","codex","decision-gate","developer-tools","evaluation","llm","markdown","planning","prd","robustness","spec-review"],"latest_commit_sha":null,"homepage":"https://github.com/devonestar/janus#readme","language":"TypeScript","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/devonestar.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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-16T10:02:08.000Z","updated_at":"2026-04-17T02:27:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/devonestar/janus","commit_stats":null,"previous_names":["devonestar/janus"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/devonestar/janus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestar%2Fjanus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestar%2Fjanus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestar%2Fjanus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestar%2Fjanus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devonestar","download_url":"https://codeload.github.com/devonestar/janus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devonestar%2Fjanus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31959886,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"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":["agent","ai","claude","cli","codex","decision-gate","developer-tools","evaluation","llm","markdown","planning","prd","robustness","spec-review"],"created_at":"2026-04-18T07:03:12.143Z","updated_at":"2026-04-18T07:03:13.022Z","avatar_url":"https://github.com/devonestar.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Janus\n\n\u003e Named after the Roman god of gates and beginnings, whose two faces look simultaneously at the past and the future.\n\n**Stop shipping fragile plans.** Janus reads your PRD, spec, or design doc and tells you which paths will break, which unknowns you're ignoring, and whether you should proceed.\n\n```bash\njanus eval my-spec.md\n# =\u003e recommend | conditional | blocked\n```\n\n---\n\n## When to Use Janus\n\nUse Janus **before committing to a plan** — not after.\n\n- You're about to merge a PRD that will drive weeks of implementation\n- You're picking between two architecture options and need a structured tiebreaker\n- You're shipping a spec that locks in an irreversible technical choice\n- You need a pre-commit gate that blocks fragile specs from entering the codebase\n- Your AI agent is about to finalize a design doc and needs a second opinion\n\n## When NOT to Use Janus\n\n- Routine code reviews (use your linter and code review tools)\n- Freeform brainstorming (too early for evaluation)\n- JSON schema validation (use ajv or zod)\n- Simple questions or clarifications\n\n---\n\n## Quick Start\n\n```bash\n# One-line install\nnpm install -g janus-gate\n\n# Or run without installing\nnpx janus-gate eval your-spec.md\n\n# Or install via shell script\ncurl -fsSL https://raw.githubusercontent.com/devonestar/janus/main/install.sh | bash\n```\n\n```bash\njanus eval your-spec.md\n```\n\nJanus returns one of three verdicts:\n\n| Verdict | Exit Code | Meaning |\n|---------|-----------|---------|\n| `recommend` | 0 | Safe to proceed |\n| `conditional` | 1 | Proceed only after resolving named unknowns |\n| `blocked` | 2 | Stop. Critical issues found |\n\nEvery verdict includes: `best_path` (what to do), `rejected_paths` (what not to do and why), and `critical_unknowns` (what you don't know yet).\n\n---\n\n## See It In Action\n\nBelow is a real verdict Janus produced on one of its own design documents — Round 10 of its dogfood series. The document was a roadmap that proposed five different ways to add named personas to Janus's evaluation pipeline. Janus was asked which one to build.\n\n```\ndecision_status:     conditional\ninformation_quality: degraded\nbest_path:           SUPPRESSED (below exact-match quorum)\n\nrejected_paths:\n  * Option P -- Parallel Specialists + Synthesizer     -\u003e violates P1\n    \"The synthesizer is itself an LLM call that can invent content\n     not present in any persona's output.\"\n  * Option R -- Red-Team vs Blue-Team                   -\u003e violates P1\n    \"The adjudicator inherits the same defect; also fails to scale\n     past two voices.\"\n  * Option S -- Principle-Sharded (P1-P7)               -\u003e violates P3\n    \"7 LLM calls x 3 min = 21 min, breaks the cost-ceiling NFR.\n     Principles are not orthogonal -- 7 critiques are partially redundant.\"\n  * Option T -- System-Prompt Shape Only                -\u003e violates P2\n    \"Ships as 'persona equipment' but delivers single-voice-with-pose.\n     The framing itself is a P2 violation.\"\n\ncritical_unknowns:\n  * U-1: The aggregator was validated for homogeneous variance.\n         Personas inject heterogeneous prompts -- is 2/3 agreement\n         consensus, or one persona having a different prior?\n  * U-2: No fixture proves personas find rejections that --samples\n         3 cannot. The hypothesis is untested.\n\nvariance_report:\n  * 3/3 samples agreed on \"conditional\"\n  * 3 samples produced three different phrasings of the same winner\n  * Quorum rule refused to name a best_path from a renaming artifact\n```\n\nFour observations about what just happened:\n\n1. **Janus did not name a winner.** Three samples agreed on what should win, but each sample phrased the name differently. Rather than pick one phrasing and pretend consensus, Janus suppressed the field. This is **P7 -- Abstention Is Correct Behavior** acting against Janus's own convenience.\n2. **Every rejection cites a principle.** No path was rejected for being \"bad\" -- each failed a specific test (P1, P2, P3). An operator reading this can argue with the principle citation, not with Janus's taste.\n3. **The critical unknowns are honest.** U-1 is a load-bearing doubt about whether Janus's own equipment (variance sampling) works on heterogeneous inputs. Janus raised it against the very round that wanted to ship that equipment.\n4. **The verdict is `conditional`, not `recommend`.** Janus sees a winner but names preconditions before implementation may proceed. A `recommend` here would have been fragile; `blocked` would have been excessive. The middle status is the one that matches the evidence.\n\nJanus evaluated its own roadmap, rejected four of five options against its own seven principles, refused to claim certainty, and named the conditions under which it would be willing to proceed. That is the tool, in one page.\n\n---\n\n## The Seven Principles\n\nEvery Janus verdict is traceable to one of these. An agent reading Janus output should respect the cited principle before overriding it.\n\n1. **P1 -- No Certainty Without Evidence.** No exact probabilities, only conditional language. Rejections say *could* violate, not *will*. If Janus has not seen evidence for a claim, the claim is not made.\n2. **P2 -- Unknowns Are First-Class.** Missing information is surfaced as a named unknown, not silently filled in. If Janus has to assume something to reach a verdict, the assumption is listed where a reader can audit it.\n3. **P3 -- Robustness Over Optimism.** Of two paths, the one that survives more failure modes wins. Ambition that has not been stress-tested loses to less ambitious paths that have been.\n4. **P4 -- Conflict Is a Rejection Signal.** Contradicting constraints invalidate every path that depends on both. Janus reads the document looking for internal inconsistency and treats it as grounds for rejection, not a puzzle to solve.\n5. **P5 -- Scope Discipline.** Janus evaluates only what the document says, not what the reader wishes it said. Opinions on adjacent topics are suppressed.\n6. **P6 -- Reversibility Preference.** Paths that preserve the ability to change course beat paths that do not. Irreversible commitments under uncertainty are downgraded.\n7. **P7 -- Abstention Is Correct Behavior.** `blocked` is a valid output, not a failure. Suppressed `best_path` is a valid output, not a gap. Refusing to answer is sometimes the most informative thing Janus can do.\n\n---\n\n## CLI Usage\n\n```bash\n# Single-shot evaluation\njanus eval my-prd.md\n\n# Variance sampling -- run N times, return consensus\njanus eval my-prd.md --samples 3\n\n# Compare two options\njanus compare option-a.md option-b.md\n\n# Autonomous Generate-Evaluate-Eliminate-Refine loop\njanus loop draft.md --max-iterations 3\n\n# CI/CD binary gate (exit 0 = pass, non-zero = fail)\njanus gate pr-spec.md\n\n# Environment and backend health\njanus doctor\njanus doctor --probe\njanus doctor --format json\n```\n\n### Flags\n\n- `--backend \u003cname\u003e` -- `claude` (default), `codex`, `opencode`, `openai-api`, `anthropic-api`, `mock`\n- `--model \u003cid\u003e` -- override backend model. Omit to honor the backend's own config\n- `--format \u003cfmt\u003e` -- `json`, `markdown`, `yaml` (`doctor`: `json` or default human text)\n- `--samples \u003cN\u003e` (eval only, v0.2.0+) -- run N times, return consensus. N in [1, 5]. Linear runtime cost.\n- `--max-iterations \u003cN\u003e` (loop only)\n\n---\n\n## What Janus Produces\n\nEvery `janus eval` or `janus compare` returns a JSON object with this shape:\n\n```ts\n{\n  decision_status: \"recommend\" | \"conditional\" | \"blocked\",\n  best_path: {\n    name: string,\n    rationale: string,\n    enabling_conditions: string[],\n    fragility_warnings: string[],\n    robustness_score: \"low\" | \"medium\" | \"high\"\n  } | null,\n  rejected_paths: [{\n    name: string,\n    rejection_reason: string,\n    violated_principle: \"P1\" | \"P2\" | ... | \"P7\" | null,\n    could_recover: boolean,\n    recovery_condition: string | null\n  }],\n  critical_unknowns: [{\n    id: string,\n    description: string,\n    impact: string,\n    question_for_human: string | null,\n    source: \"missing_field\" | \"inferred_assumption\" | \"information_asymmetry\" | \"external_dependency\"\n  }],\n  assumptions: [...],\n  information_quality: \"sufficient\" | \"degraded\" | \"insufficient\",\n  next_actions: [{ priority: \"critical\"|\"high\"|\"medium\", action: string, addresses: string }],\n  variance_report?: {              // present only when --samples \u003e 1\n    samples: number,\n    decision_status_trace: DecisionStatus[],\n    decision_status_agreement: number,\n    best_path_agreement: number | null,\n    tie_broken_to: DecisionStatus | null,\n    rejected_path_frequency: Record\u003cstring, number\u003e,\n    critical_unknown_frequency: Record\u003cstring, number\u003e,\n    per_sample_errors: (string | null)[]\n  }\n}\n```\n\n---\n\n## Quick Facts\n\n| Field | Value |\n|-------|-------|\n| Current version | `0.3.2` |\n| npm package | `janus-gate` (`npm i -g janus-gate` or `npx janus-gate`) |\n| Binary | `janus` (on `$PATH` after install) |\n| Default backend | `claude` (headless Claude Code CLI -- no API key) |\n| Commands | `eval`, `compare`, `gate`, `loop`, `doom`, `doctor` |\n| Output formats | `json` (default off-TTY), `markdown` (default on TTY), `yaml` |\n| Exit codes | `0=recommend`, `1=conditional`, `2=blocked`, `3=error` |\n| Requires | Node 18+, TypeScript, one of: Claude Code CLI / Codex CLI / OpenAI API key / Anthropic API key |\n| Source | `https://github.com/devonestar/janus` |\n| Repo layout | `src/` (TS), `dist/` (built JS), `specs/` (internal design docs), `marketplace/` (plugin), `integrations/` (skill + hook + AGENTS) |\n\n---\n\n## Backends\n\n| Backend | Status | Notes |\n|---------|--------|-------|\n| `claude` (default) | verified | Local Claude Code CLI, headless (`-p --output-format json`). Uses subscription, no API key. |\n| `codex` | verified | Local Codex CLI. Honors `~/.codex/config.toml` default model unless `--model` given. |\n| `opencode` | untested | Local OpenCode CLI. |\n| `openai-api` | untested | Needs `OPENAI_API_KEY`. |\n| `anthropic-api` | untested | Needs `ANTHROPIC_API_KEY`. |\n| `mock` | verified | Rule-based, no LLM. For fast CI and structural checks. |\n\n### Cost notes\n\nOn the default `claude` headless backend:\n- Short fixture (\u003c 1 KB): ~40 s per eval\n- Typical PRD (5-10 KB): ~1-2 min per eval\n- Large roadmap (15+ KB): ~2-3 min per eval\n- `--samples N` multiplies wall-clock by N (serial). Default timeout is 240 s per call.\n\nUse `--backend mock` when you want structure-only checks with no LLM cost.\n\n---\n\n## Agent Integration\n\nJanus is consumed by other agents via the plain CLI -- no MCP needed.\n\nThese are **optional adapters on top of the CLI product**.\n\n### Option 1 -- Claude Code plugin\n\n```bash\nclaude plugin marketplace add ./marketplace\nclaude plugin install janus@janus-local\n```\n\nAfter a session restart, Claude Code auto-triggers the `janus` skill on PRD/spec work.\n\n### Option 2 -- Global CLAUDE.md snippet\n\nCopy the `JANUS_PROMPT_BLOCK` from `integrations/skill/SKILL.md` into your `~/.claude/CLAUDE.md`.\n\n### Option 3 -- Codex CLI / OpenCode / Git hook\n\n- **Codex CLI**: paste `integrations/codex/project-instructions.md` into your project's `AGENTS.md`\n- **OpenCode**: install `integrations/skill/SKILL.md` at `~/.config/opencode/skills/janus/SKILL.md`\n- **Git pre-commit gate**: copy `integrations/git-hook/pre-commit` to `.git/hooks/pre-commit`\n\nMCP server implementation is archived under `reserved/mcp.ts` and can be reinstated if needed.\n\n---\n\n## Self-Dev Pipeline\n\nJanus includes a built-in feature development loop for spec-driven work:\n\n```bash\n# Full pipeline: intake check -\u003e eval -\u003e loop -\u003e validator\nnpm run self-dev -- my-spec.md claude\n\n# Intake structure check only\nnpm run check:intake -- my-spec.md\n\n# Variance probe: run --samples 3 N times, measure jitter\nscripts/variance.sh 10 fixtures/smoke.md\n```\n\nThe self-dev pipeline runs four stages in sequence:\n\n1. **Intake** -- verifies the spec has required headings (Context/Problem, Goal, Constraints, Options, Unknowns, Decision requested)\n2. **Eval** -- single-shot `janus eval` on the spec\n3. **Loop** -- `janus loop --max-iterations 3` for autonomous refinement\n4. **Validator** -- auto-selected by filename pattern (canonical identity, candidate paths, or none)\n\nValidators are registered in `scripts/self-dev.mjs`. To add a new one, add an entry to `validatorRegistry` with a filename regex and command array.\n\n---\n\n## Dogfood Ledger\n\nJanus has been self-evaluated fourteen times. Each round Janus evaluates one of its own design documents, applies its own principles, and the result drives the next change.\n\n| Round | Focus | Outcome |\n|-------|-------|---------|\n| 1 | Initial self-eval | Found internal P4 contradiction in own spec |\n| 2 | Remediation | First `recommend` + first `loop success` |\n| 3 | Robustness | First `high` robustness verdict; inline-summary pattern proven |\n| 4 | Rename Agamoto -\u003e Janus | Verified functionally equivalent |\n| 5 | Self-future decision | Janus picked its own next step, executed it |\n| 6 | MCP integration | Built and verified, then archived per operator preference |\n| 7 | Non-MCP integration | Skill + git-hook + Codex-AGENTS path shipped |\n| 8 | Equipment roadmap | Janus chose variance-sampling (Option G) over 3 alternatives |\n| 9 | Ship sampling | v0.2.0 with `--samples N`; discovered unknown-coverage is the larger value |\n| 10 | Persona roadmap | Janus picked Q x Source-C; rejected 7 alternatives; named 3 preconditions for Round 11 |\n| 11 | README storytelling | Janus picked Option E (Concrete-Evidence-First); rejected 3 alternatives including metaphor-first |\n| 12 | Doom Gate spec | Janus picked Option A (dedicated `doom` command + schema); rejected 3 alternatives (B=P4, C=P3, D=P4); conditional on grounding validation |\n| 13 | Doom Gate ship | U-1 grounding experiment passed (5/5); `janus doom` implemented and verified on mock + claude backends |\n| 14 | Doctor --probe spec | Janus picked Option A (--probe + exit codes + JSON in one cycle); loop terminated acceptable at iteration 3 (stagnant on U-1/U-2) |\n\n---\n\n## Roadmap\n\nCurrent public surface:\n\n- `eval`, `compare`, `loop`, `gate`\n- `--samples N` consensus sampling on `eval`\n- CLI-first integrations under `integrations/`\n- self-dev pipeline (`npm run self-dev`) for spec-driven feature development\n- archived MCP implementation under `reserved/mcp.ts` (not part of the shipped surface)\n\nWork in progress / not yet shipped:\n\n- persona-gated PR / merge workflow\n- rejected-path canonicalization under sampling (first increment shipped in `bd9c5b6`)\n- failure future narratives (`failure_chain` field on rejected paths)\n- Doom Gate: adversarial pre-mortem command (`janus doom`) — shipped in v0.3.0\n\n---\n\n## Changelog\n\n- **0.3.2** -- Fix: `janus --version` now reads version from `package.json` dynamically instead of a hardcoded string.\n- **0.3.1** -- Fix: `janus doctor` no longer exits non-zero when zero LLM backends are installed. The command is diagnostic/informational; only Node \u003c 18 (non-probe) or a failed `--probe` now causes non-zero exit. Unblocks CI runners with no LLM CLIs installed.\n- **0.3.0** -- Feature: `janus doom` adversarial pre-mortem command. Accepts markdown files or inline text. Dedicated DoomReport schema with severity/survivability/survival_rating. Honest Futures Bar 6/6 achieved.\n- **0.2.2** -- Fix: Claude backend `--tools \"\"` flag prevents recursive tool invocation. New structural test guard. Doom Gate spec added (Round 12 dogfood).\n- **0.2.1** -- Fix: default `claude` backend timeout 120 s -\u003e 240 s. Previously long docs (\u003e 10 KB) could SIGTERM under samples.\n- **0.2.0** -- Feature: `--samples N` on `janus eval`. New optional `variance_report` output field. Deterministic aggregation (majority vote + conservative tie-break + union of rejections/unknowns).\n- **0.1.1** -- Internal: removed MCP from shipped surface (archived under `reserved/`). Default backend switched to `claude` headless.\n- **0.1.0** -- Initial dogfood-verified CLI: `eval` / `compare` / `loop` / `gate`.\n\n---\n\n## Reading Guide\n\n- **If you are an agent picking up this README as context**: extract the \"When to Use\" section, the Quick Start, the seven principles, the output schema, and the exit codes. Those let you invoke Janus correctly and interpret its output.\n- **If you are a human first-reader**: the \"See It In Action\" block is the shortest honest answer to \"what does this tool actually do.\" Read that, then the principles, and you have the philosophy. Everything after is mechanics.\n- **If you are evaluating adoption**: decide whether the seven principles match your team's failure modes. If they do, the rest is integration detail. If they don't, no amount of README polish will fix that.\n\n---\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevonestar%2Fjanus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevonestar%2Fjanus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevonestar%2Fjanus/lists"}