{
  "markdown": "# Praxis\n\nA plugin that turns the workflow rules you already wrote in `CLAUDE.md` into things\nthat actually fire at the moment they are needed — a merge that stops while a blocking\nreview finding is still open, a \"done\" that will not go out without evidence behind it,\na worktree workflow that is not skipped because the change looked small. Skills you\ninvoke by name, and hooks that fire whether or not anyone remembers them. One runtime,\npackaged for Claude Code, Codex, and Cursor.\n\n> **Note:** Skills may be added, removed, or restructured at any time without prior notice. This is a personal toolbox — not a stable API.\n\n## The name\n\n*Praxis* (πρᾶξις) is theory carried into action — where a stated principle stops being a\nstatement and becomes something done. That is this repository's whole design, written in\n[`ETHOS.md`](ETHOS.md) as **spec defines, hook enforces**: every hook here is the\nstructural enforcement of a rule that already existed as prose in a `CLAUDE.md` or a\nmemory entry, and exists precisely because the prose had already failed at the moment it\nwas needed. The skills sit on the same axis — `strike`, `debt`, `spec-drift`, and\n`merge-briefing` all make an already-decided rule reachable at execution time rather\nthan deciding anything new.\n\nThe word carries none of that domain on its own, which is what the paragraph above is\nfor. It is also a crowded name: the Praxis API framework (Ruby), PraxisEMR, and several\nunrelated npm and PyPI packages share it. None of them share a namespace with this\nrepository — the surfaces that resolve here are `devseunggwan/praxis`, the `praxis:`\nskill prefix behind `/praxis:retrospect`, and the `PRAXIS_*` environment variables.\n\n## Installation\n\n### Claude Code — plugin (recommended)\n\n```bash\n/plugin marketplace add https://github.com/devseunggwan/praxis\n/plugin install praxis\n```\n\nClaude Code reads `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`\ndirectly from the repo root.\n\n### Codex — marketplace + plugin\n\n```bash\n# Register this repo as a marketplace (its root is .agents/plugins/marketplace.json)\ncodex marketplace add https://github.com/devseunggwan/praxis\ncodex plugin install praxis\n```\n\nCodex reads `.agents/plugins/marketplace.json` as the marketplace root and\n`plugins/praxis/.codex-plugin/plugin.json` as the plugin root. The `skills/`,\n`hooks/`, and `scripts/` directories inside `plugins/praxis/` are symlinks\ninto the repo-root runtime — there is no source duplication.\n\n### Direct skill install (fallback)\n\nWhen the plugin surface isn't available, Claude Code still loads personal\nskills from `~/.claude/skills/<skill-name>/SKILL.md` (project skills from\n`.claude/skills/`). Clone the repo and link the skill directories you want:\n\n```bash\ngit clone https://github.com/devseunggwan/praxis.git ~/projects/praxis\nmkdir -p ~/.claude/skills\nln -s ~/projects/praxis/skills/<skill-name> ~/.claude/skills/<skill-name>\n```\n\nSkills installed this way are invoked as `/<skill-name>` rather than\n`/praxis:<skill-name>`, and the hooks are not installed — this path ships\nskills only. Skills that call a bundled helper through `CLAUDE_PLUGIN_ROOT`\n(`strike`, `spec-drift`, the `cmux-*` skills) need that variable exported to\nthe clone path, e.g. `export CLAUDE_PLUGIN_ROOT=~/projects/praxis`.\n\n## Where to start\n\nThree reading paths, each 3–4 steps. Time estimates are for a first read.\n\n**Fix or add a hook** (~25 min)\n\n1. [`ETHOS.md` → Hook Ethos](ETHOS.md#hook-ethos) — why a hook exists at all and what it may never do (5 min)\n2. [`DESIGN.md` → Adding a new hook](DESIGN.md#adding-a-new-hook) — the shared contracts and the per-hook checklist (10 min)\n3. The hook's own `hooks/<role>/<name>/spec.md`, found via [`docs/hook/INDEX.md`](docs/hook/INDEX.md) — what it blocks, passes, and how it fails open (5 min)\n4. [`CONTRIBUTING.md` → Adding or modifying a hook](CONTRIBUTING.md#adding-or-modifying-a-hook) — registration, tests, and the runtime canary (5 min)\n\n**Change a skill** (~15 min)\n\n1. [`RUNTIME_CONSTRAINTS.md`](RUNTIME_CONSTRAINTS.md) — the fixed Claude Code limits a skill must fit inside (5 min)\n2. [`skills/SKILL.md.tmpl`](skills/SKILL.md.tmpl) — the frontmatter and section skeleton to copy (2 min)\n3. [`CONTRIBUTING.md` → Adding or modifying a skill](CONTRIBUTING.md#adding-or-modifying-a-skill) — the live-runtime verification gate (8 min)\n\n**Change packaging or manifests** (~10 min)\n\n1. [`ARCHITECTURE.md` → Multi-Platform Packaging](ARCHITECTURE.md#multi-platform-packaging) — canonical source, generated outputs, add-a-platform flow (6 min)\n2. [`CONTRIBUTING.md` → Packaging](CONTRIBUTING.md#packaging) — which files are generated and how to regenerate them (4 min)\n\n## Skills\n\nEighteen skills, grouped as Discovery, Development, Discipline, and Session Management.\nThe full table — trigger keywords, when to use each, example invocation — lives in\n[`docs/skills.md`](docs/skills.md).\n\nIf you are new, `/praxis:using-praxis` maps situations onto the skill that handles each —\nsessions lost to a crash, a broken rule you want on record, a review whose comments have\npiled up — which is a shorter read than the full table. The three worth knowing by name\non day one:\n\n| Skill | What it is for |\n| ------- | ---------------- |\n| `/praxis:using-praxis` | Finding the right skill when you don't know what exists yet |\n| `/praxis:retrospect` | After a session that went badly — find the friction's root cause and act on it |\n| `/praxis:merge-briefing` | Before merging — probe all three finding surfaces, then brief and ask |\n\nPraxis also ships `bypass-review`, a shell wrapper with no `SKILL.md`. It is **not**\ninvocable as `/praxis:*`; it reads the review bypass-telemetry event logs. See\n[CONTRIBUTING.md → Local development](CONTRIBUTING.md#local-development) for every\nshipped CLI wrapper.\n\n## Hooks\n\nHooks are the larger half of praxis: **99 hooks**, registered at 114 points across\n`PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PostToolBatch`, `Stop`,\n`SubagentStart`, `SubagentStop`, `UserPromptSubmit`, and `SessionStart`. They run\nwithout being invoked, so this section is the one to read before installing — it is what\nchanges about your session.\n\nThey divide into four roles. Two of them block by default, and a third can be\npromoted into blocking:\n\n| Role | Count | What it does |\n| ------ | ------- | -------------- |\n| `preflight-gate` | 37 | Inspects a tool call before it runs and can deny it |\n| `completion-verify` | 13 | Fires at `Stop` — can block a response that claims completion without evidence |\n| `advisory-nudge` | 44 | Prints a warning to stderr and lets the call through — 18 read a `PRAXIS_*_STRICT` variable that makes them stop the call instead |\n| `postuse-correction` | 5 | Reacts after a tool call — telemetry, follow-up signals |\n\nConcretely, what a gate stops looks like this — `gh issue create` without a duplicate\nsearch first (`block-gh-issue-create-without-dup-search`), an edit to a file while you\nare standing on a protected branch (`pre-edit-protected-branch-guard`), a merge run from\nthe wrong worktree (`gh-merge-worktree-precondition`), `gh search --state all` which that\nsubcommand does not accept (`block-gh-state-all`), a foreground `sleep`-and-poll loop\n(`foreground-poll-loop-guard`), a commit whose title breaks the repo's format\n(`commit-title-format-check`).\n\nTwo properties are load-bearing. **Hooks fail open**: a missing `jq`, a malformed stdin\npayload, an unreadable transcript — all exit 0, so a broken hook degrades to no hook\nrather than to a broken session. And most blocks arrive with their own way out: the\nshared deny-message helper (`hooks/_lib/block_message.py`) prints the hook's bypass\nvariable in the message, so you rarely have to go looking for it.\n\nThe complete list, with each hook's events, hosts, strict/bypass knobs, and the external\ncommands it may run, is the generated\n[Hook Operating Matrix](docs/hook-operating-matrix.md). Per-hook specs live at\n`hooks/<role>/<name>/spec.md`, indexed by [`docs/hook/INDEX.md`](docs/hook/INDEX.md),\nand [DESIGN.md → Hook Design Contracts](DESIGN.md#hook-design-contracts) covers the\ncontracts every hook follows.\n\n## Turning it off\n\nA hook that blocks something you meant to do is not a wall. There are three levers.\n\n**One gate.** 61 of the 99 hooks declare an opt-out or tuning variable. Which variable\nbelongs to which hook, and what setting it actually does to that hook, is the table in\n[`docs/bypass-vars.md`](docs/bypass-vars.md); the generated\n[Hook Operating Matrix](docs/hook-operating-matrix.md) carries the same mapping with each\nhook's default alongside it. Read the row before setting the variable — the hooks differ\nfrom each other, which is why this section points at the table instead of summarizing it.\n\n**Set it where Claude Code can see it** — its own environment, before the session starts:\n\n```bash\nexport PRAXIS_HOOK_BYPASS_SKILL_GATE=1   # <one-line reason>\n```\n\nAn assignment written in front of the command (`VAR=1 git …`) does **not** work. Hooks\nread `os.environ` of their own process, which never sees a variable scoped to the tool\ncall, so the gate blocks exactly as before. Use the shell export above, or the `env`\nblock in your `settings.json`.\n\n**All of it.** On a plugin install, `claude plugin disable praxis` (or `/plugin` in the\nsession) switches the whole plugin off — skills and hooks together, since both are\ndeclared in one manifest and `disable` has no hook-only option. To keep the skills and\nstop a gate, use the opt-out above instead. Only a manual install registers praxis hooks\nin `settings.json` as separate entries; there, dropping them leaves the skills working.\n\n## Prerequisites\n\nMost skills delegate to external agents or session managers. Install the dependencies that match your usage tier.\n\n| Dependency | Required for | Install |\n| ------------ | ------------- | --------- |\n| **gh CLI** | Standalone (`recover-sessions`), strike skills, PR/issue ops | `brew install gh` |\n| **jq** | Strike skills (session-scoped counter parsing) | `brew install jq` |\n| **oh-my-claudecode** | Agent delegation (tracer, analyst, critic, code-reviewer) | `omc install` |\n| **cmux** | Session management skills (cmux-*) | Mac app installer |\n| **codex-cli, gemini-cli** | Multi-provider routing in `cmux-delegate` | per upstream docs |\n\n### Hook dependencies\n\nHooks fail open, so a missing component never breaks a session — the hooks that\nkey on it simply never fire, and nothing says so. `hooks/manifest.json` declares\nthose components per hook in its `requires` field (#1158); this table is the\nreader's view of that field, and `scripts/check-plugin-manifests.py` Rule 27\nchecks the two against each other in both directions (#1332).\n\n| Component | Hooks inert without it | Install |\n| ----------- | ------------------------ | --------- |\n| `cmux` | `model-routing-advisory` | Mac app installer (the Full tier below) |\n| `codex-plugin` | `codex-review-route` | `/plugin marketplace add openai/codex-plugin-cc`, then `/plugin install codex@openai-codex` |\n| `hookable-memory-store` | `memory-hint` | a memory directory whose entries carry `hookable:` frontmatter, located per `hooks/_lib/_memory_dir.py` (`PRAXIS_MEMORY_DIR` overrides) |\n| `zsh` | `block-unmatched-glob` | `brew install zsh`, or the distro package |\n\n`builtin-task-postuse` is the one hook whose premise is another plugin rather\nthan a component: it corrects an oh-my-claudecode `pre-tool-enforcer` false\npositive and is registered for the Claude host only (`hosts`), so it carries no\n`requires` row. None of these components is declared as a `plugin.json`\n`dependencies` entry — the harness has no optional-dependency concept, so a\ndeclaration would turn every tier below into a hard requirement; see\n[ARCHITECTURE.md → Why `plugin.json` declares no `dependencies`](ARCHITECTURE.md#why-pluginjson-declares-no-dependencies).\n\n### Compatibility Tiers\n\n| Tier | What works | What you need |\n| ------ | ----------- | --------------- |\n| **Standalone** | recover-sessions, strike / strikes / reset-strikes, debt | `gh` CLI, `jq`; `recover-sessions` also needs `tmux`; `debt` needs only `git` |\n| **Enhanced** | + retrospect, codex-review-wrap | + oh-my-claudecode |\n| **Full** | + all cmux-* skills | + cmux |\n| **Multi-provider** | + codex/gemini routing in cmux-delegate | + codex-cli, gemini-cli |\n\n> Skills in higher tiers fall back to manual/built-in alternatives when their dependencies are missing, but with reduced functionality.\n\n## Provider Routing\n\nSkills that dispatch external CLI workers (`cmux-delegate`) can route tasks\nto multiple AI providers via a unified `--model` flag using\n`<provider>:<model>` notation (e.g. `claude:opus`, `codex:o3`,\n`gemini:flash`). Bare names (`opus`, `sonnet`, `haiku`) always resolve to\nClaude — full backward compatibility. When only `claude` is installed,\nthe system behaves exactly as before — no errors, no degradation.\n\nSee [ARCHITECTURE.md → Provider Routing](ARCHITECTURE.md#provider-routing) for\nthe full task-type / complexity routing matrix and fallback policy.\n\n## Packaging internals\n\nPlatform manifests are generated, not hand-edited. The canonical source is\n`manifests/plugin.base.json` (common metadata) plus one file per platform\nunder `manifests/platforms/`.\n\n```bash\n# Regenerate every platform manifest + adapter shell symlinks\n./scripts/build-plugin-manifests.py\n\n# Verify committed manifests match the canonical source (CI / pre-merge)\n./scripts/check-plugin-manifests.py\n```\n\nGenerated artifacts are committed:\n\n- `.claude-plugin/plugin.json`\n- `.claude-plugin/marketplace.json`\n- `.agents/plugins/marketplace.json`\n- `plugins/praxis/.codex-plugin/plugin.json`\n- `plugins/praxis/{skills,hooks,scripts}` (symlinks into repo root)\n\nTo add a new platform, add a `manifests/platforms/<name>.json` file listing\nits outputs, add its `host_id` to the `hosts` enum in\n`hooks/manifest.schema.json` (a test asserts the enum and the platform set\nare equal), and run the build script — no changes to skills, hooks, or\nexisting platforms required.\n\n## Local Development\n\nWhen you work from a clone rather than the plugin cache, the CLI wrappers\nshipped by skills (`cmux-recover-sessions`, `claude-recover`,\n`cmux-save-sessions`, …) are installed as `~/.local/bin` symlinks into\nwhichever clone ran `scripts/install.sh` — so a patch reaches the version that\nruns at the shell only if it lands in that clone. One clone per machine keeps\nthe links honest; `verify-symlinks.sh` tells you when they are not.\n\n```bash\n# Install / refresh CLI symlinks (idempotent)\n./scripts/install.sh\n\n# Verify symlinks point at this clone (CI / SessionStart hook)\n./scripts/verify-symlinks.sh\n```\n\nSee [CONTRIBUTING.md → Local development](CONTRIBUTING.md#local-development) for\nthe full list of shipped CLI wrappers and drift-recovery rationale.\n\n## Security & Privacy\n\n- [SECURITY.md](SECURITY.md) — vulnerability reporting and supported versions\n- [PRIVACY.md](PRIVACY.md) — what praxis reads, executes, and never transmits\n\n## License\n\nMIT License\n",
  "bytes": 15026,
  "sha": "c5dd3268cf28219b39dbc7d6caebc98126673bc8a83184f8a0d6aaa64619c355",
  "repo_slug": "devseunggwan/praxis",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_devseunggwan_praxis_8e687e46/readme"
}