@magic-spells/constellation
v0.7.0
Published
Files-first architecture planning for AI-assisted development. Your project plan as markdown cards in the repo — typed, connected, queryable, and diffable with git.
Maintainers
Readme
Constellation
Your project's architecture plan as markdown files in the repo: typed cards, connected into a graph, validated by lint, diffed by git, readable by humans on GitHub and by AI agents with nothing more than file access.
constellation/
plan.md ← the living project plan (PLAN-PROJECT)
api/API-TICKETS.md ← one file per card; the filename IS the handle
datatype/DATATYPE-TICKET.md
db/DB-TICKETS.md
flow/FLOW-CREATE-TICKET.md
...Each card is frontmatter (structure) + markdown (narrative). Connections come from
frontmatter: a plain connections: list of handles, plus handle-shaped values in
other frontmatter fields. A [[HANDLE]] link in prose or a handle used as a Mermaid
node ID is a hyperlink — clickable, linted, but never a graph edge. The indexer
derives the graph; nothing derived is ever stored.
Why files? Plans drift from code when they live somewhere else. Here a plan
change is a commit: it rides the same branch and PR as the code it describes,
merges per-card, and "what changed in the plan" is git diff -- constellation/.
Install
npm install -g @magic-spells/constellation # the `constellation` binary
# or run without installing:
npx @magic-spells/constellation lintRequires Node ≥ 22.
Usage
constellation init # scaffold constellation/ with a starter plan.md
constellation lint # validate handles, references, folders, schemas
constellation rename A-X A-Y # rename a card + rewrite every reference to it
constellation mcp # run the MCP server (stdio) for AI agents
constellation serve # open the local viewer (editable; --readonly to disable)
constellation repos # list sibling repos declared in connected_repos
constellation add skills # install the authoring skill into ~/.claude, ~/.codex, ~/.cursor, ~/.agents
constellation version # print the CLI version (`v` also works)
constellation upgrade # npm install -g @magic-spells/constellation@latestLint errors (broken graph: bad handles, dangling structured references, duplicates) exit non-zero for CI; warnings (wrong folder, schema violations, unknown fields, dangling prose links) don't block.
Repo layout
| Path | What |
|---|---|
| constellation/ | Constellation's own plan — the format spec, MCP design, and architecture as connected cards (formerly docs/); also a flagship real-world plan |
| schemas/ | JSON Schemas: card.json (reserved keys) + one per type |
| skill/ | AI authoring skill: SKILL.md + per-type references with golden examples |
| src/core/ | Parser, reference extraction, indexer, schema validation, lint |
| src/cli/ | The constellation binary (init, lint, rename, mcp, serve, repos, add skills, version, upgrade) |
| src/mcp/ | MCP server: hydrated retrieval, validated writes, git tools |
| viewer/ | The Puzzle single-page viewer — themes, card pages, neighborhood diagrams |
| examples/constellation/ | Golden sample plan — one card of every type, lints clean, doubles as the test fixture |
Development
npm install
npm test # vitest
npm run lint:examples # lint the golden plan
npm run build # tsc → dist/MCP
constellation mcp exposes the plan to AI agents over stdio:
- Self-serving:
orientopens a session with the whole plan at a glance in one small call;describe_typehands back a card type's schema and authoring guidance, so an agent can write correct cards with no skill installed. - Hydrated retrieval:
get_card,search, andtraversecan return connected cards with their complete frontmatter and body in one call.list_cardsandtraversefilter by status —["planned", "building", "none"]is the backlog view (everything not yet built). - Validated writes:
create_card/create_cards,update_card,append_note/edit_section(byte-cheap memory writes),set_verified,rename_card(rewrites every reference plan-wide),delete_card,add_connection(s),remove_connection— every write lints and returns issues. Body-only updates never reformat frontmatter. - Queryable memory:
searchmatches appended note text;list_noteslists notes across cards by kind (every gotcha / decision in one call). - Git-powered change tracking:
diff_plan(per-card changes since the sync marker),plan_log,set_sync_point,stale_report/check_sync(bound-code drift since a card was verified),check_integrity. - Connected repos (multi-repo): a plan can declare sibling repos
(
add_connected_repo/list_connected_repos/remove_connected_repo); every tool takes an optionalreposelector to read or write a sibling's plan — or a package's plan in a monorepo (see Monorepos). Omit it and single-repo behavior is unchanged. - Visual viewer:
start_viewer/stop_vieweropen and close the local web viewer from inside an agent session, returning a clickable URL.
Add to Claude Code
Run from your repo root, so the server starts there and finds the plan:
# Run straight from npm — no install needed:
claude mcp add constellation -- npx -y @magic-spells/constellation mcp
# Or, if installed globally (npm i -g @magic-spells/constellation):
claude mcp add constellation -- constellation mcp
# Share with everyone who clones the repo (writes .mcp.json):
claude mcp add --scope project constellation -- npx -y @magic-spells/constellation mcpManage it with claude mcp list, claude mcp get constellation, and
claude mcp remove constellation.
To build a plan from an existing codebase (or audit one), ask the agent to bootstrap or
audit — the server ships bootstrap_plan and audit_plan prompts (slash commands
in Claude Code) that walk the code macro→micro: follow the data, follow the user/auth, then
step back and pressure-test the plan for blind spots (missing unhappy paths, auth gaps,
forgotten cross-cutting concerns) and recommend. The full method is in
skill/methodology.md.
Add to Codex
Codex CLI keeps MCP servers in ~/.codex/config.toml (TOML, not JSON). Add it with the CLI:
# Run straight from npm — no install needed:
codex mcp add constellation -- npx -y @magic-spells/constellation mcp
# Or, if installed globally (npm i -g @magic-spells/constellation):
codex mcp add constellation -- constellation mcp…or hand-edit the config (a project-scoped .codex/config.toml also works in trusted repos):
[mcp_servers.constellation]
command = "npx"
args = ["-y", "@magic-spells/constellation", "mcp"]
cwd = "/path/to/your/repo" # so the server walks up to your planLaunch codex from your repo root (or set cwd above) so the server starts there and finds
the plan — otherwise tools return NO_PLAN_FOUND. Run /mcp inside a Codex session to confirm
it's connected; manage it with codex mcp list and codex mcp remove constellation.
Other MCP clients
Hand-edit the client's config (Claude Desktop, a project .mcp.json, etc.):
{
"mcpServers": {
"constellation": {
"command": "constellation",
"args": ["mcp"],
"cwd": "/path/to/your/repo"
}
}
}Set cwd to your repo root (or any folder inside it). The server finds the plan by
walking up from its working directory; without cwd it inherits the client's, which
may not be your project — in which case tools return NO_PLAN_FOUND.
Monorepos
A plan doesn't have to live at the git root. In a monorepo each package keeps its own plan, and the root holds at most a thin signpost that routes to them:
packages/puzzle/constellation/plan.md ← the framework's plan
packages/puzzle-pieces/constellation/plan.md ← the registry's plan
constellation/plan.md ← signpost: connected_repos, no cardsA card's path: and code_refs are relative to its plan's code root — the
folder containing that constellation/ dir, or the code_root field on the
plan's frontmatter. Staleness, the version check, commit scoping and code
attachment all follow the code root, so each package measures drift against its
own history.
The signpost is plan.md and nothing else: its connected_repos names the
package plans (puzzle → packages/puzzle), so repo=puzzle addresses that
plan from any MCP tool. Never init_plan a full plan at a monorepo root —
architecture cards belong to the package plans, and cards never connect across
plans.
constellation serve at a monorepo root hosts every plan in the repo from
one server, with a plan-switcher dropdown in the viewer; --plan <id> picks
which one opens by default, and constellation serve <path> still serves exactly
one. Discovery runs at startup and never crosses into a nested .git, so a
brand-new plan needs a restart.
Single-repo behavior is unchanged: the code root is the repo root, there's no dropdown, and every path and URL stays what it was.
Viewer
constellation serve renders the plan as a local website, editable in place
(pass --readonly to disable writes). Five colour schemes toggle in the header —
observatory (dark, star-field; the default), default, warm, void and
dim — each with a light / dark / follow-system switch.
The Overview page is a status board for the plan:
- a health strip — the freshness verdict, the counts that qualify it (cards, connections, integrity, drift), and a Set sync point button that stamps the baseline every claim card is measured against
- Releases — every
RELEASEcard newest-first, the one still in flight expanded with itsFEATUREcards grouped Breaking / Features / Fixes / Chores (from each feature'schange:field), the shipped ones collapsed and openable. A release describes itself from the features pointing at it — never a hand-written changelog - Activity — plan commits and code commits in one stream, tagged by kind
- Code drift — the cards whose bound code moved since they were last verified, as a verdict rather than a list, with the fix named when nothing is tracked yet
- Notes — the latest
append_notememory across cards
Card pages show structured fields, the
markdown body, connection chips in both directions, and a small constellation
diagram of the card's neighborhood — its nodes tinted by card type. Mermaid blocks
render in-browser, [[HANDLE]] links navigate, and the page live-reloads when plan
files change on disk.
constellation serve # http://localhost:4747 (walks upward if busy; assets ship prebuilt)
npm run build:viewer # only when developing from sourceIn an agent session you don't need the CLI — ask Claude to open the viewer and it
calls the start_viewer MCP tool, which returns the URL (stop_viewer closes it).
