Universal project operating system for AI coding assistants
Project description
holoctl
A living project operating system for AI coding assistants. One source of truth in
.holoctl/, compiled to whatever Claude Code, GitHub Copilot, OpenAI Codex, or any AGENTS.md-aware tool (Aider, Zed, Junie, Jules, Factory, gooseโฆ) reads. Durable cross-assistant memory, autonomous curator, multi-target compile, MCP server, web dashboard โ all version-controlled next to your code.
๐บ๐ธ English | ๐ง๐ท Portuguรชs
TL;DR โ three commands
# 1. Install (pick one โ see "Installation" if `hctl` is not on PATH)
uv tool install holoctl # recommended
# or: pipx install holoctl
# or: pip install holoctl # โ ๏ธ requires an active venv (see below)
# 2. Plant the global router (once per machine, per assistant)
hctl setup-global --target all # Claude + Copilot
# (Codex picks up the per-project AGENTS.md + .codex/config.toml emitted by `hctl init`.)
# 3. Initialize a project
cd ~/my-project && hctl init
Open Claude Code (or any supported assistant) in ~/my-project and type /holoctl. The agent reads the workspace, runs discovery, suggests specialist personas, populates context, and shows the overview โ autonomously.
Table of contents
- Why holoctl
- Anatomy of
.holoctl/ - Installation โ including the
pipvenv gotcha - Per-machine global setup
- Per-project initialization
- The
/holoctlslash command โ what it actually does - Cross-tool compilation
- MCP vs CLI โ design choice
- Daily workflows
- Command reference
- Configuration
- Lifecycle hooks
- Per-assistant guide โ Claude / Copilot / Codex
- Coverage and doctor
- Privacy & coexistence
- Troubleshooting
- FAQ
- Migration from projctl / projhub
- Roadmap
- Documentation & license
Why holoctl
Every AI coding assistant defines its own native primitives โ Claude Code skills, Copilot prompts, Codex .codex/config.toml, AGENTS.md for everything else. Maintaining the same project context across all of them is manual, error-prone, and never up-to-date.
holoctl is the abstraction that's missing from the ecosystem: you write project context once in .holoctl/, the compiler materializes the right native files for every tool. Plus a CLI, a Kanban board, a memory layer that survives across sessions, an event journal, an autonomous curator that proposes structural improvements, an MCP server, and a web dashboard โ all built around the same source of truth.
It's "living" because it wakes up between sessions:
- Durable memory at
.holoctl/memory/โ the same notes appear in Claude (as skills), Copilot (as.github/instructions/), and Codex (via AGENTS.md) in each one's native shape. - Event journal captures every tool use, edit, and session boundary via hooks plumbed automatically.
- Autonomous curator watches the journal and proposes new personas, path-scoped rules, or topic archives as
meta:curatetickets on the board. Approve a suggestion by moving the ticket todoneโ it auto-executes. - Token-economy boot prints โค1KB of session-zero context (top pendings, recent decisions, available topics) so the assistant doesn't burn tokens loading the whole
CLAUDE.md. - MCP server exposes board / memory / journal / curator as standard tools (with per-tool permission gating in Claude Code).
Anatomy of .holoctl/
your-project/
โโโ .holoctl/ โ single source of truth, committed to git
โ โโโ config.json โ project name, prefix, board statuses, targets
โ โโโ instructions.md โ compiled to CLAUDE.md / AGENTS.md / .codex/AGENTS.override.md / .github/copilot-instructions.md
โ โ
โ โโโ board/ โ Kanban + tickets
โ โ โโโ WORKFLOW.md โ state machine doc (template-managed)
โ โ โโโ index.json โ auto-rebuilt projection of tickets/*.md
โ โ โโโ tickets/PRJ-001-*.md โ each ticket = one Markdown file with frontmatter
โ โ
โ โโโ agents/ โ active personas (only `boardmaster` after `hctl init`)
โ โ โโโ boardmaster.md โ library (developer / reviewer / architect / researcher / dba / devops / security-auditor / tech-writer / agent-designer) added on demand, or design a new one with `/agent-new`
โ โ
โ โโโ commands/ โ /board, /ticket, /spec, /sprint, /close, /decision, /status, /agent-new
โ โ
โ โโโ context/ โ project-level prose
โ โ โโโ objective.md โ What / Why / Success criteria
โ โ โโโ architecture.md โ Tech stack / Structure / Patterns / Boundaries
โ โ โโโ conventions.md โ Code style, naming, testing
โ โ โโโ decisions/ โ ADR-style hard locks
โ โ โโโ documents/ โ free-form supporting docs
โ โ
โ โโโ memory/ โ durable cross-assistant notes
โ โ โโโ MEMORY.md โ always-on index
โ โ โโโ .gitignore โ excludes `_archived/` by default
โ โ โโโ topics/ โ lazy / glob / always_on topics
โ โ
โ โโโ journal/ โ daily JSONL of session events
โ โ โโโ 2026-05-08.jsonl
โ โ
โ โโโ curator/ โ curator state + per-ticket metadata
โ โ
โ โโโ hooks/ โ (optional) declarative hooks per lifecycle event
โ โโโ rules/ โ (optional) path-scoped rules with `paths:` frontmatter
โ โโโ skills/ โ (optional) custom skills with progressive disclosure
โ โโโ output_styles/ โ (optional) Claude-specific output styles
โ โโโ ignore โ (optional) gitignore-style for assistant-specific ignore lists
โ โ
โ โโโ activity.jsonl โ raw activity log (low-level)
โ
โโโ โฆyour code
โ
โโโ (compiled outputs โ usually .gitignored)
โโโ AGENTS.md โ cross-tool universal (Codex / Aider / Zed / Junie / โฆ)
โโโ CLAUDE.md โ Claude Code
โโโ .claude/ โ Claude Code agents/commands/settings.json
โโโ .github/ โ Copilot instructions + prompts + memory instructions
โโโ .vscode/mcp.json โ MCP server config for Copilot-in-VSCode
โโโ .codex/ โ OpenAI Codex: AGENTS.override.md + config.toml (mcp_servers)
Optional folders (
hooks/,rules/,skills/,output_styles/,ignore) are not created byhctl init. They're opt-in surfaces you create when you need them. Compilers only emit what exists in the source โ empty input produces empty output (anti-overengineering).
Installation
Requires Python โฅ 3.11.
Option A โ uv tool (recommended)
uv tool install holoctl
hctl --version
uv tool creates an isolated venv automatically and puts hctl on your PATH. Nothing else needed.
Option B โ pipx
pipx install holoctl
hctl --version
Same isolation as uv tool. Requires pipx (pip install pipx && pipx ensurepath).
Option C โ pip (โ ๏ธ requires an active venv)
pip install holoctlfrom a "naked" Python on a modern OS will fail witherror: externally-managed-environment(PEP 668), or โ if you bypass that โ install into the system Python andhctlmay end up in a directory not on your PATH.
The reliable way is to create a venv specifically for holoctl and activate it before running hctl:
# Linux / macOS
python3 -m venv ~/.venvs/holoctl
source ~/.venvs/holoctl/bin/activate
pip install holoctl
hctl --version
# Windows (PowerShell)
python -m venv $HOME\.venvs\holoctl
& $HOME\.venvs\holoctl\Scripts\Activate.ps1
pip install holoctl
hctl --version
# Windows (cmd.exe)
python -m venv %USERPROFILE%\.venvs\holoctl
%USERPROFILE%\.venvs\holoctl\Scripts\activate.bat
pip install holoctl
hctl --version
Caveat with venv-based pip install: hctl only works while the venv is activated. To make it always available, add a wrapper:
# Linux/macOS โ add to ~/.bashrc or ~/.zshrc
alias hctl="$HOME/.venvs/holoctl/bin/hctl"
# Windows โ add to $PROFILE
function hctl { & "$HOME\.venvs\holoctl\Scripts\hctl.EXE" $args }
This is exactly the kind of friction that uv tool and pipx avoid. If you have any choice, use one of those.
Optional ML extra
uv tool install "holoctl[ml]" # ~250MB โ adds ONNX paraphrase detection to the curator
Verifying the install
hctl --version # 0.17.0+
hctl --help # full command list
hctl doctor --global # checks ~/.claude and ~/.copilot install (will report 'missing' until step 2)
Per-machine global setup
hctl setup-global plants the /holoctl router in each AI tool's user-level config, so the slash command works in any folder โ even before hctl init.
hctl setup-global --target all # Claude + Copilot
hctl setup-global --target claude # only Claude Code
hctl setup-global --target copilot # only Copilot CLI
hctl setup-global --target all --dry-run # preview without writing
What gets installed:
| Tool | File | Format | Idempotent block |
|---|---|---|---|
| Claude Code | ~/.claude/commands/holoctl.md + ~/.claude/skills/holoctl-router/ |
Slash command + skill with references | replaces files |
| Copilot | ~/.copilot/AGENTS.md |
Markdown section appended | <!-- holoctl:start โฆ end --> markers |
Codex and other AGENTS.md-aware assistants (Aider, Zed, Junie, Jules, Factory, goose) pick up the per-project AGENTS.md emitted by hctl compile --target agents โ they have no documented user-level surface for slash routers, so setup-global is a no-op for them.
Detecting drift:
hctl doctor --global
Output:
holoctl: global-check
โ Claude router up-to-date (~/.claude/commands/holoctl.md)
โ Copilot holoctl block present (~/.copilot/AGENTS.md)
All global routers up-to-date.
Per-project initialization
Inside a project folder:
cd ~/my-project
hctl init
What init does, in order:
- Creates
.holoctl/structure (board, agents, commands, context, memory, journal). - Writes
config.jsonwith inferred project name (=cwd.name), prefix (= initials), and the shipped provider catalog (Linear / GitHub / Trello / Azure DevOps / Jira / Slack โ URL patterns mapped to MCP fetch tools). - Seeds
boardmaster.md(the only mandatory persona โ owns ticket lifecycle). All other personas (developer / reviewer / architect / researcher / dba / devops / security-auditor / tech-writer / agent-designer) stay latent in the library untilhctl agent add <name>or/agent-newactivates them. - Seeds
instructions.md,WORKFLOW.md, ticket_template.md, and eight default commands (/status,/ticket,/spec,/board,/sprint,/decision,/close,/agent-new). - Plants Claude lifecycle hooks (
SessionStartโhctl boot,Stopโhctl handoff, deny-list for derived files) and built-in reactive skills (holoctl-router,holoctl-spec-flow,holoctl-provider-mcp,holoctl-work-item-router,holoctl-persona-suggester,holoctl-ticket-discipline,holoctl-memory-discipline,holoctl-parallel-evaluator). - Writes MCP server config (
.claude/settings.json:mcpServers.holoctl). - Compiles default targets (
agents+claude).
Flags:
hctl init --name "My Project" --prefix "MP" # explicit
hctl init --targets agents,claude,copilot,codex # custom target set
hctl init --bare # skeleton only โ skip compile/hooks/MCP
hctl init --skip-compile # init but don't compile yet
Re-running hctl init in an already-initialized workspace is idempotent โ it re-syncs template-managed files (commands/*.md, WORKFLOW.md, _template.md, boardmaster.md) without touching user-owned files (tickets, hand-edited agents, context docs, custom rules/skills/hooks).
If you upgrade holoctl after init, run:
hctl upgrade --check # show CHANGELOG slice
hctl upgrade # apply migrations + recompile
The /holoctl slash command
This is the routing brain. After steps 2 + 3 above, type /holoctl (or invoke the equivalent skill) in any assistant. The agent runs:
hctl doctor
The first line of output is router-friendly โ one of:
| First line | Flow | What the agent does next |
|---|---|---|
holoctl: not initialized |
Flow A | hctl init โ discover codebase โ suggest personas โ seed memory โ hctl overview |
holoctl: outdated |
Flow B | hctl upgrade --check, ask for confirmation, then hctl upgrade + hctl boot |
holoctl: ok |
Flow C | hctl boot (โค1KB teaser), react to pending tickets / curator suggestions |
Flow A in detail (the most important one โ first time in a project):
- Detect.
hctl doctorreturnsnot initialized. - Init.
hctl init --name "<inferred>" --prefix "<PRX>". - Discover. Reads in parallel: README, package files (
package.json,pyproject.toml,Cargo.toml,go.mod, โฆ), top-level dirs, lint configs, existing AI configs (read-only โ never overwrites). - Configure.
- Sub-repos: if multiple sub-projects detected, one aggregated question ("Found backend/, frontend/, mobile/. Register all?"), then
hctl repo addfor each approved. - Context files: writes
.holoctl/context/{objective,architecture,conventions}.mdand.holoctl/instructions.mddirectly from what was read. No per-file confirmation. - Ambiguity escape: if README is generic/missing, one question to clarify objective. Otherwise no questions.
- Sub-repos: if multiple sub-projects detected, one aggregated question ("Found backend/, frontend/, mobile/. Register all?"), then
- Suggest personas.
hctl agent suggestmaps detected stack โ personas from the expanded library (developer / reviewer / architect / researcher / dba / devops / security-auditor / tech-writer / agent-designer). Examples: SQL +migrations/โdba;.github/workflows/+Dockerfile+ Terraform โdevops;docs/with many.mdโtech-writer. When no library entry fits the repo,/agent-new <name>invokesagent-designerto draft a persona tailored to your stack. - Memory seed. Creates
.holoctl/memory/topics/project-overview.mdwith a 3-5 line paragraph derived from README + package files. This is whathctl bootreads in session 2 so the agent "wakes up" knowing what the project is. - Overview & next action. Runs
hctl overview(canonical snapshot) andhctl boot(teaser). Reacts: proposes creating the first ticket, or surfaces curator suggestions, or points to next p1.
Total time: ~30 seconds, with 1-2 questions in the path.
Cross-tool compilation
hctl compile reads .holoctl/ and emits files in each target's native format. Targets:
hctl compile --target agents # AGENTS.md (cross-tool universal)
hctl compile --target claude # CLAUDE.md + .claude/...
hctl compile --target copilot # .github/copilot-instructions.md + .github/prompts/... + .vscode/mcp.json
hctl compile --target codex # .codex/AGENTS.override.md + .codex/config.toml (mcp_servers)
hctl compile # all targets in config.targets[]
The agents target emits AGENTS.md at the repo root โ the agents.md standard adopted by OpenAI Codex, Aider, Zed, JetBrains Junie, Google Jules, Factory, goose, and other agents.md-aware tools. Always include it in your targets (the default config does).
Coverage matrix โ what each compiler emits from each .holoctl/ source:
.holoctl/ source |
claude | copilot | codex | agents |
|---|---|---|---|---|
instructions.md |
CLAUDE.md |
.github/copilot-instructions.md |
.codex/AGENTS.override.md |
AGENTS.md (Objective/Architecture) |
agents/*.md |
.claude/agents/<n>.md |
โ | โ | โ |
commands/*.md |
.claude/commands/<n>.md |
.github/prompts/<n>.prompt.md |
โ | โ |
context/*.md |
(via instructions/memory) | (via instructions) | (via instructions override) | AGENTS.md body |
memory/topics/*.md |
.claude/skills/holoctl-mem-* |
.github/instructions/holoctl-mem-* |
โ | โ |
hooks/*.json (opt) |
.claude/settings.json merge |
.copilot/config.json merge |
โ | โ |
rules/*.md (opt) |
.claude/rules/<n>.md |
โ | โ | โ |
skills/<n>/SKILL.md (opt) |
.claude/skills/<n>/... |
โ | โ | โ |
output_styles/*.md (opt) |
.claude/output_styles/ |
โ | โ | โ |
| MCP servers (config) | .claude/settings.json:mcp |
.vscode/mcp.json |
.codex/config.toml:mcp_servers |
โ |
See
hctl coveragefor a live, workspace-specific version of this table.
MCP vs CLI
Current design: skills and agents prefer MCP, fall back to CLI / paste
Since v0.17, slash commands, agents, and reactive skills prefer the MCP server when it's running, falling back to hctl CLI (or paste, for external content) when not. Examples:
- Boardmaster calls
mcp__holoctl__board_create({...})first; CLIhctl board add '<json>'is the documented fallback. /specinvokes theholoctl-provider-mcpskill to fetch an external card body via the provider's MCP (Linear / GitHub / Trello / Azure DevOps / Jira / Slack โ or a custom internal board registered viahctl provider add); paste is the fallback, withsource_*preserved either way. The MCP server is auto-spawned by Claude (via.claude/settings.json:mcpServers), Copilot (via.vscode/mcp.json), or Codex (via.codex/config.toml:[mcp_servers.holoctl])./agent-newcallsmcp__holoctl__agent_createto materialize a designed persona; manual.mdediting remains the escape hatch.- The
/holoctlrouter still runshctl doctor/hctl init/hctl bootover the shell โ these don't have MCP equivalents because they bootstrap or terminate the assistant session itself.
The CLI remains the source of truth โ every MCP tool maps 1:1 to a hctl subcommand โ but MCP is the preferred path inside the assistant's loop because of finer permission gating, in-process speed after handshake, and structured JSON output that chains naturally.
The MCP server
hctl init writes the MCP config so each assistant can spawn hctl serve --mcp on demand. The server exposes 25 tools:
| Read tools (auto-approved) | Write tools (permissions.ask) |
|---|---|
holoctl.board_list |
holoctl.board_create |
holoctl.board_children |
holoctl.board_batch |
holoctl.board_get |
holoctl.board_move |
holoctl.board_show |
holoctl.board_set |
holoctl.memory_list_topics |
holoctl.board_ack |
holoctl.memory_read_topic |
holoctl.board_note |
holoctl.memory_search |
holoctl.board_delete |
holoctl.journal_recent |
holoctl.board_batch_move |
holoctl.agent_list_available |
holoctl.board_batch_set |
holoctl.curate_suggestions |
holoctl.board_batch_delete |
holoctl.config_show |
holoctl.memory_add |
holoctl.agent_add |
|
holoctl.agent_create |
|
holoctl.curate_silence |
holoctl.config_show is what the holoctl-provider-mcp skill reads to discover the provider catalog at runtime โ no hardcoded URL list inside the skill.
MCP-preferred trade-offs
| Concern | CLI | MCP |
|---|---|---|
| Universality | Runs in any terminal, any agent, any shell. | Requires MCP-aware client. |
| Reproducibility | Human can re-run the exact same command. | Tool calls are JSON-RPC, less human-friendly to replay. |
| Speed | Fork of Python (~80-150ms cold). | In-process after handshake (faster after first call). |
| Permission gating | Coarse โ relies on shell allow-lists. | Fine-grained โ per-tool, write-tools land in ask. |
| Output | Rich text formatted for humans. | Structured JSON for machines/chains. |
The CLI is always the fallback. If the MCP server is down (or never started), the assistant uses hctl directly and everything still works โ including from a plain terminal with no AI tool at all.
Daily workflows
Spec-Driven Development (/spec)
Turn an external card or a multi-paragraph brief into a structured spec in .holoctl/, then automatically decompose it into parallel-safe child tasks.
/spec https://linear.app/eng/issue/ENG-42
What happens:
- Provider MCP discovery. The
holoctl-provider-mcpskill matches the URL against the configured provider catalog (hctl provider list). If the Linear MCP is connected (.mcp.json), it fetches the card body directly. If not, it falls back to "paste the body here" โ withsource_provider,source_ref,source_url,source_labelpreserved either way. - Discuss. One batched question to refine scope, acceptance criteria, files touched, edge cases. Skips when the source content is already explicit.
- Materialize spec.
mcp__holoctl__board_create({kind: "spec", source_*, acceptance, context, ...}). - Decompose.
holoctl-parallel-evaluatorsplits the work into disjoint child tasks; boardmaster callsmcp__holoctl__board_batch({shared: {parent: SPEC_ID, source_*, ...}, tickets: [...]}). The CLI rejects the batch if any two children touch the same file. - Propose execution. "Activate
developeronPRJ-NNN+1?"
You can also /spec with free-form text (no URL) โ same flow without the MCP fetch step.
External board providers (hctl provider)
Manage the catalog that maps URL patterns โ MCP fetch tool names. Shipped defaults cover Linear, GitHub, Trello, Azure DevOps, Jira, and Slack.
hctl provider list # show current catalog with status
hctl provider test linear https://linear.app/eng/issue/ENG-42 # dry-run the URL match
hctl provider enable linear # auto / always / disabled
hctl provider disable jira
# Add a custom internal board:
hctl provider add acme \
--mcp-fetch mcp__acme__get_card \
--url-pattern '^https?://board\.acme\.corp/c/(?P<ref>[A-Z0-9]+)' \
--label-template '{ref}: {title}'
When the catalog and the MCP tool both line up, /spec and holoctl-work-item-router use the fetch transparently. When the MCP isn't connected, the skills fall back to paste โ never silently fake a fetch.
Create a ticket
hctl board add '{
"title": "Add JWT auth",
"agent": "developer",
"priority": "p1",
"projects": ["backend"],
"goal": [
"JWT signing implemented",
"Unit tests cover happy + invalid token",
"Lint and build pass"
],
"context": "Sessions are cookie-based today; OAuth landing requires bearer."
}'
Or in chat: "create a p1 ticket for JWT auth, developer persona, with goal: signing, tests, lint". The agent (boardmaster) translates and runs the command.
Parallel-safe batch creation
hctl board batch '{
"shared": { "tags": ["par:auth-flow"], "projects": ["backend"] },
"tickets": [
{ "title":"JWT signing", "agent":"developer", "priority":"p1", "files":["src/auth/jwt.py"], "goal":["sign() emits HS256","tests"] },
{ "title":"Auth middleware", "agent":"developer", "priority":"p1", "files":["src/middleware/auth.py"], "goal":["verify+expiry","tests"] },
{ "title":"Auth integration tests", "agent":"reviewer", "priority":"p1", "files":["tests/test_auth.py"], "goal":["happy/expired/invalid"] }
]
}'
The CLI rejects the batch if any two tickets touch the same file (proves non-overlap before creating anything).
Move tickets
hctl board move PRJ-001 doing
hctl board set PRJ-001 priority p0
hctl board ls --status doing --priority p1
Memory
hctl memory add api-conventions --scope glob -g "src/api/**" \
-d "API naming, error envelope, pagination"
hctl memory list
hctl memory search "JWT"
hctl memory get api-conventions # read body
hctl memory archive old-topic # moves to topics/_archived/
Topic scopes:
always_onโ always included in the assistant's context (use sparingly).lazyโ referenced in MEMORY.md, agent loads when relevant.globโ only loaded when the assistant is editing files matching the glob.
Personas
hctl agent list # active vs library
hctl agent suggest # heuristic โ what to activate based on codebase
hctl agent suggest --json # machine-readable for automation
hctl agent add developer # materialize from library
hctl agent add custom --from developer # copy active agent as base
hctl agent remove developer # deactivate (still in library)
Library (v0.17): developer, reviewer, architect, researcher, dba, devops, security-auditor, tech-writer, agent-designer. hctl agent suggest matches paths: globs against your repo (e.g. **/*.sql โ dba, **/.github/workflows/** โ devops).
When no library entry fits the repo, design a new one tailored to your stack:
/agent-new payments-specialist
The slash command delegates to the agent-designer persona, which reads the repo (README, package files, top-level dirs), drafts a schema-correct persona body (name / description / tools / paths / model), saves it as .holoctl/agents/<name>.draft.md, and asks for confirmation before materializing via mcp__holoctl__agent_create. The reactive holoctl-persona-suggester skill also surfaces "want a new persona for this gap?" whenever work touches paths no active persona owns.
Closing a session
hctl handoff # appends 1 line to memory/topics/session-trail.md
hctl handoff --note "Shipped 0.14" # plus a custom note
If lifecycle hooks are installed (hctl init does this for Claude), Stop runs hctl handoff --auto automatically โ you don't need to remember.
Session boot (cross-session continuity)
hctl boot # โค1KB teaser
hctl boot --target claude # records source in journal
hctl boot --plain # ASCII (no Rich color codes โ used by hooks)
Output example:
## My Project โ sessรฃo 7
Pendรชncias p0/p1: PRJ-003 Add JWT auth, PRJ-005 Fix N+1 in /tickets
Decisรตes recentes: 2026-05-04-jwt-vs-sessions, 2026-05-01-monorepo
Topics: api-conventions, decisions, session-trail
Personas ativas: boardmaster, developer, reviewer
โก 2 sugestรฃo do curador (PRJ-042, PRJ-043) โ `hctl curate show`
Curator
hctl curate run --auto # rate-limited (1/day, 14-day suppression per pattern)
hctl curate show # open meta:curate tickets
hctl curate apply PRJ-042 # run the proposed action manually
hctl curate silence <pattern_id> # 14-day suppression
hctl board move PRJ-042 done # โ approval auto-executes the action
Web dashboard
hctl serve # http://127.0.0.1:4242
hctl serve --host 0.0.0.0 --port 8000 # opt-in network exposure (warns: no auth)
Tabs: Board (Kanban / List / Tree views with SSE updates), Repos, Agents, Commands, Context.
MCP server
hctl serve --mcp # stdio MCP server โ assistants spawn this on demand
Configured automatically by hctl init so you don't run it manually. Test it standalone with --mcp.
Command reference
| Command | What it does |
|---|---|
hctl init |
Create or sync .holoctl/ (idempotent). |
hctl setup |
Plant /holoctl skill in every detected assistant (legacy โ see setup-global). |
hctl setup-global --target X |
Install the global router for tool X (Claude / Copilot / all). |
hctl upgrade |
Migrate workspace + recompile to installed version. |
hctl compile --target X |
Generate AI-tool integration files. Default = config.targets[]. |
hctl serve [--mcp] |
Web dashboard (4242), or stdio MCP server. |
hctl doctor [--global] |
Health check. First line = router-friendly. |
hctl coverage [--only-present] [--target X] |
Matrix of .holoctl/ source โ per-target outputs. |
hctl overview |
One-screen workspace snapshot. |
hctl boot [--target X] |
โค1KB session-zero context. Recorded in journal. |
hctl handoff [--note "..."] |
Append session-trail line. Auto-called by Stop hook. |
hctl board <ls|add|move|set|batch|get|body|stat|rebuild-index> |
Tickets. |
hctl agent <list|suggest|add|remove> |
Personas (library + active). |
hctl provider <list|add|enable|disable|test|remove> |
External-board catalog โ URL pattern โ MCP fetch tool. |
hctl memory <list|add|get|search|archive|seed> |
Durable memory. |
hctl journal <record|show|count|tail|import> |
Event journal. |
hctl curate <run|show|apply|silence> |
Autonomous curator. |
hctl repo <list|add|info> |
Subprojects (auto-discovered + manual overrides). |
Every command supports --help.
Configuration
.holoctl/config.json โ only override what you need:
{
"holoctlVersion": "0.17.0",
"project": {
"name": "My Project",
"prefix": "MP",
"repos": [
{ "path": "./backend", "name": "backend", "description": "FastAPI service" }
]
},
"board": {
"statuses": ["backlog", "doing", "review", "done", "cancelled"],
"priorities": ["p0", "p1", "p2", "p3"],
"idPadding": 3
},
"git": { "checkDirty": false },
"targets": ["agents", "claude", "copilot", "codex"],
"server": { "port": 4242, "theme": "dark" },
"providers": {
"linear": { "enabled": "auto", "url_pattern": "...", "mcp_fetch_tool": "mcp__linear__get_issue", "label_template": "{ref}: {title}" },
"github": { "enabled": "auto", "url_pattern": "...", "mcp_fetch_tool": "mcp__github__get_issue", "label_template": "{org}/{repo}#{ref}: {title}" }
/* trello, azure_devops, jira, slack shipped too โ see `hctl provider list` */
}
}
Notes:
targetscontrols whathctl compileemits when called with no--target. Adding a target requireshctl compile --target Xonce to materialize.git.checkDirtydefaults to false โ holoctl reads.git/HEAD/refs/configdirectly without spawninggit status. Instant on Windows + corporate AV.board.idPadding: 3producesMP-001(vs 2 โMP-01).providersis populated additively onload_configโ workspaces from older versions get the shipped defaults automatically. Usehctl provider add/enable/disableinstead of hand-editing.- Adding a new field to a ticket: just write it in the
.mdfrontmatter and runhctl board rebuild-index.
Lifecycle hooks
hctl init writes .claude/settings.json with hooks plumbed by default:
{
"hooks": {
"SessionStart": [
{ "type": "command", "command": "hctl journal record session_start --source claude --quiet" },
{ "type": "command", "command": "hctl boot --plain --target claude",
"description": "Print session-zero teaser before user types" }
],
"PreToolUse": [
{ "type": "command", "matcher": "Edit|Write",
"command": "hctl journal record write_attempt --stdin --quiet --deny-glob '.holoctl/board/index.json,.holoctl/memory/MEMORY.md,.holoctl/activity.jsonl'",
"description": "Block direct writes to derived state โ force CLI usage" }
],
"PostToolUse": [
{ "type": "command", "command": "hctl journal record tool_use --stdin --quiet" }
],
"Stop": [
{ "type": "command", "command": "hctl journal record stop --quiet" },
{ "type": "command", "command": "hctl handoff --quiet --auto",
"description": "Persist session-trail on every Stop. --auto skips trivial sessions." }
]
},
"permissions": {
"ask": [ "mcp__holoctl__board_create", "mcp__holoctl__memory_add", "..." ],
"deny": [ "Write(.holoctl/board/index.json)", "Edit(.holoctl/memory/MEMORY.md)", "..." ]
}
}
The deny list is the enforcement for the rule "never edit derived state by hand" โ even if the agent forgets the instruction, the harness blocks the tool call.
Copilot receives .copilot/config.json (allow/deny lists). Codex doesn't expose a public per-project hooks API โ its lifecycle is handled by the user agent and AGENTS.md content.
Per-assistant guide
Claude Code
After hctl setup-global --target claude and hctl init:
- Slash command:
/holoctl(your global router). - Project context:
CLAUDE.md+@.holoctl/memory/MEMORY.mdreference (auto). - Subagents:
.claude/agents/<name>.mdโ invokable via theAgenttool. - Hooks:
.claude/settings.json:hooks(boot teaser on SessionStart, handoff on Stop, deny-list on PreToolUse). - MCP:
.claude/settings.json:mcpServers.holoctlrunshctl serve --mcp.
# Verify
hctl doctor # workspace health
hctl doctor --global # router install drift
ls .claude/ # agents/, commands/, settings.json
GitHub Copilot
After hctl setup-global --target copilot and hctl init:
- Global:
~/.copilot/AGENTS.mdโ appended block with<!-- holoctl:start โฆ end -->markers. - Project:
.github/copilot-instructions.md,.github/prompts/<name>.prompt.md. - Memory:
.github/instructions/holoctl-memory-*.instructions.mdwithapplyTo:glob. - MCP:
.vscode/mcp.json. - Permissions: deny-list and allow-list flags via
.copilot/config.json.
Copilot accumulates AGENTS.md content (doesn't overwrite) โ the holoctl block coexists with anything else you have.
OpenAI Codex
After hctl init with codex in config.targets (or hctl compile --target codex):
- Project AGENTS.md at the repo root (emitted by the
agentstarget โ Codex reads this natively per the spec). - Codex-specific override:
.codex/AGENTS.override.mdโ compiled from.holoctl/instructions.md. Codex merges this on top of the rootAGENTS.md, so it's the right place for Codex-only guidance without polluting the cross-tool file. - MCP:
.codex/config.toml:[mcp_servers.holoctl]declares the holoctl stdio server. Codex loads.codex/config.tomlonce you trust the project (codex trust .or the prompt on first run).
No setup-global step โ Codex has no documented user-level surface for slash routers.
Aider / Zed / Junie / Jules / Factory / goose / others
Any tool that respects AGENTS.md reads the file emitted by hctl compile --target agents. No tool-specific config needed for these โ just keep agents in your config.targets (it ships there by default).
Coverage and doctor
hctl coverage
Shows the fork between source and target:
hctl coverage # all sources ร all targets
hctl coverage --only-present # only sources that exist in this workspace
hctl coverage --target claude # only one target column
Output (filtered):
hctl coverage (source โ per-target outputs)
workspace: /home/me/my-project
active targets: agents, claude, copilot, codex
Source | agents | claude | copilot | codex
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
instructions.md | โ AGENTS | โ CLAUDE.md | โ .gh/copi.md | โ .cx/AGENTS.override
agents/*.md | โ | โ .cl/agents | โ | โ
commands/*.md | โ | โ .cl/comma | โ .gh/prompts | โ
memory/topics/*.md | โ | โ .cl/skills | โ .gh/instr | โ
(MCP servers) | โ | โ settings | โ .vsc/mcp | โ .cx/config.toml
hctl doctor
hctl doctor # workspace health
hctl doctor --global # global router install drift
First line is router-friendly (parsed by /holoctl):
holoctl: not initializedโ no.holoctl/found at or above cwd.holoctl: outdatedโ workspaceholoctlVersion< installedhctl --version.holoctl: okโ workspace at current version.holoctl: global-checkโ--globalmode.
Privacy & coexistence
hctl initwrites nothing to$HOME. Onlyhctl setup-globaldoes โ and only the router files in user-scope locations of detected assistants.- No machine-wide registry, no daemon, no telemetry, no auto-update check. Workspace =
.holoctl/next to your code. That's the entire footprint. .holoctl/memory/.gitignoreships with_archived/excluded by default. Privacy-strict workspaces uncomment two lines to make the whole memory tree local-only.- Coexists with native auto-memory. Claude Code's auto-memory is not disabled.
holoctladds a@.holoctl/memory/MEMORY.mdreference toCLAUDE.mdso Claude reads both sources. - Compiled outputs are best
.gitignore'd (.claude/,.codex/,.github/copilot-instructions.md,AGENTS.md,CLAUDE.md) โ they're regenerated from.holoctl/. Some teams prefer to commit them for new contributors who don't haveholoctlinstalled yet.
Troubleshooting
hctl: command not found
uv tool/pipx: should be on PATH automatically. If not, runuv tool update-shellorpipx ensurepathand reopen the terminal.pipinstall: if you didn't use a venv, you hit PEP 668 or installed into the wrong Python. Re-do it via the venv method in Installation.- Workaround:
python -m holoctl <subcommand>works regardless of PATH (as long as the venv is active).
/holoctl does nothing
- Run
hctl doctor --global. Probably you skippedhctl setup-global. Run it. - For Codex/Aider/Zed/other AGENTS.md-aware tools: no global router โ they consume the per-project
AGENTS.mdemitted byhctl compile --target agents.
No .holoctl/ found
- You're not in a project that's been
hctl init'd. Either runhctl inithere, orcdinto a project that has.holoctl/. find_project_rootwalks up the tree looking for.holoctl/config.json. If you're inside a subfolder of a project, it should still find it.
hctl init says "Refusing to downgrade"
- The workspace was created with a newer
hctl. Either upgrade yourhctl(uv tool upgrade holoctl) or manually edit.holoctl/config.json:holoctlVersion(not recommended).
Compile produces stale outputs / hctl doctor --global always says "drift"
- The user-edited their global router by hand โ drift detected. Run
hctl setup-global --target X --forceto overwrite, or accept the drift if intentional.
Window edition / Powershell / hctl path issues
- The legacy global router (pre-0.14) had a hardcoded venv path. If you're upgrading from before 0.14: run
hctl setup-global --target claudeto replace it with the PATH-based version.
MCP server not responding
hctl serve --mcpis stdio-only. The assistant spawns it via the MCP config; check.claude/settings.json:mcpServers.holoctl.commandresolves to a validhctl(orpython -m holoctl).- Set
HOLOCTL_BIN=/abs/path/to/hctlenv var to override the auto-detection.
Tests fail with No module named 'httpx'
tests/test_dashboard.pyusesfastapi.testclientwhich requireshttpx.httpxis declared inpyproject.toml's[dependency-groups].dev(PEP 735) โ picked up automatically byuv sync. If you're using plainpip(no uv), install it manually:pip install httpx pytest. The CI matrix usesuv sync --frozenand runs the full test suite without skipping.
FAQ
Do I have to use the slash command? Can I use hctl directly?
Yes. The CLI is the source of truth โ slash commands are conveniences. Everything is doable from a terminal.
Can I use this without the AI assistant?
Yes. hctl board, hctl memory, hctl serve work fine standalone. You get a Kanban + memory layer + MCP server even without any AI tool.
Does this conflict with Claude Code's auto-memory?
No โ they coexist. Claude reads both CLAUDE.md (which references .holoctl/memory/MEMORY.md) and its native auto-memory. The curator can promote durable patterns from auto-memory into versioned topics.
Can I share .holoctl/ across multiple repos in a monorepo?
Yes โ that's the design. hctl init at the monorepo root, then hctl repo add ./backend ./frontend ./mobile. Tickets can declare projects: [backend, shared].
How do I add a new compile target (e.g. for a new AI tool)?
Add a module in holoctl/lib/compiler/<name>.py exposing compile_<name>(project_root, config, dry_run), register in compiler/__init__.py. See CONTRIBUTING.md.
Where's the data stored?
Everything in .holoctl/, in your repo, version-controlled by you. No cloud, no database, no daemon.
Can I customize the persona library?
Yes. The library lives in holoctl/templates/agents/ (read-only when installed via PyPI). To customize: clone the repo, edit, and pip install -e . for local dev. Or override per-project: hctl agent add custom --from developer then edit .holoctl/agents/custom.md.
The agent ignores my context files
Check that .holoctl/instructions.md is being compiled (not .holoctl/context/objective.md directly). The compile pipeline merges context โ instructions โ CLAUDE.md/AGENTS.md/etc. Run hctl coverage --only-present to see what's flowing where.
Migration from projctl / projhub
Earlier names of this project. holoctl reads .projctl/ and .projhub/ directories and auto-renames them to .holoctl/ on the next save. Tickets that used scope: X are read as projects: [X] and rewritten on the next board set or rebuild-index.
No manual migration needed โ open a projctl/projhub workspace with hctl 0.14+ and it's silently upgraded.
If you had ~/.claude/commands/projctl.md or projhub.md: run hctl setup-global --target claude to install the new holoctl.md and delete the legacy ones manually.
Roadmap
- Two-way provider sync โ close the original card on the external board when the holoctl spec reaches
done(currently the assistant just gets a reminder). - Expanded provider catalog defaults โ community-contributed entries for less common boards (ClickUp, Asana, Notion, internal RFC systems).
- Curator v2 โ structural pattern detection (e.g., "you keep editing the same 3 files together; want a rule?").
.holoctl/skills/ecosystem โ community-shared skills with progressive disclosure (cross-tool by compile).- VS Code extension โ board view + memory navigation in the IDE.
- Multi-workspace dashboard โ
hctl serve --multifor monorepos with many subprojects.
Documentation & license
- CHANGELOG.md โ release notes
- ARCHITECTURE.md โ internal design, compile pipeline, threat model
- SECURITY.md โ vulnerability reporting + threat model
- CONTRIBUTING.md โ dev setup, conventions, how to add a compile target
- docs/README.pt-br.md โ Portuguese version of this README
MIT ยฉ Felipe Carillo
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file holoctl-0.19.0.tar.gz.
File metadata
- Download URL: holoctl-0.19.0.tar.gz
- Upload date:
- Size: 341.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ff3f60d0f35eee720b87acc07e0981435991c85f424d8d3cd9758c66521745d
|
|
| MD5 |
01be9a5b76e5da0b204597a0b39a2254
|
|
| BLAKE2b-256 |
b777740a177ed8fb731037285411be622097b52ee315be4eb8e5459348e69efa
|
Provenance
The following attestation bundles were made for holoctl-0.19.0.tar.gz:
Publisher:
release.yml on FelipeCarillo/holoctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
holoctl-0.19.0.tar.gz -
Subject digest:
1ff3f60d0f35eee720b87acc07e0981435991c85f424d8d3cd9758c66521745d - Sigstore transparency entry: 1654859128
- Sigstore integration time:
-
Permalink:
FelipeCarillo/holoctl@ee7497f30ea145858e4de7c9aa53d47ad71cd04d -
Branch / Tag:
refs/tags/v0.19.0 - Owner: https://github.com/FelipeCarillo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee7497f30ea145858e4de7c9aa53d47ad71cd04d -
Trigger Event:
push
-
Statement type:
File details
Details for the file holoctl-0.19.0-py3-none-any.whl.
File metadata
- Download URL: holoctl-0.19.0-py3-none-any.whl
- Upload date:
- Size: 327.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93d57fde74f69b2857a6be7684de1183acb26a3ff0a58f5385153fc073cd256b
|
|
| MD5 |
31bab475de2243af1560a13ca92fa8b7
|
|
| BLAKE2b-256 |
ec43f01c6b37c3ef7c4025fc1301a783dd24346d9e659f51a1a9103527a739b2
|
Provenance
The following attestation bundles were made for holoctl-0.19.0-py3-none-any.whl:
Publisher:
release.yml on FelipeCarillo/holoctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
holoctl-0.19.0-py3-none-any.whl -
Subject digest:
93d57fde74f69b2857a6be7684de1183acb26a3ff0a58f5385153fc073cd256b - Sigstore transparency entry: 1654859232
- Sigstore integration time:
-
Permalink:
FelipeCarillo/holoctl@ee7497f30ea145858e4de7c9aa53d47ad71cd04d -
Branch / Tag:
refs/tags/v0.19.0 - Owner: https://github.com/FelipeCarillo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee7497f30ea145858e4de7c9aa53d47ad71cd04d -
Trigger Event:
push
-
Statement type: