Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "context-tree",
"interface": { "displayName": "Context Tree" },
"plugins": [
{
"name": "context-tree",
"source": {
"source": "npm",
"package": "@first-tree-ai/context-tree",
"version": "latest"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Developer Tools"
}
]
}
21 changes: 21 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "context-tree",
"owner": {
"name": "First Tree AI",
"url": "https://github.com/first-tree-ai"
},
"metadata": {
"description": "Install the complete Context Tree plugin for linked, durable project context."
},
"plugins": [
{
"name": "context-tree",
"description": "Complete Context Tree plugin for linking, reading, and publishing durable project context.",
"source": {
"source": "npm",
"package": "@first-tree-ai/context-tree",
"version": "latest"
}
}
]
}
12 changes: 12 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "context-tree",
"version": "0.1.2",
"description": "Complete Context Tree plugin with linking, reading, durable writes, and a packaged CLI.",
"author": {
"name": "First Tree AI"
},
"homepage": "https://github.com/first-tree-ai/context-tree",
"repository": "https://github.com/first-tree-ai/context-tree",
"license": "Apache-2.0",
"keywords": ["context-tree", "memory", "agents"]
}
28 changes: 28 additions & 0 deletions .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "context-tree",
"version": "0.1.2",
"description": "Complete Context Tree plugin with linking, reading, durable writes, and a packaged CLI.",
"author": {
"name": "First Tree AI",
"url": "https://github.com/first-tree-ai"
},
"homepage": "https://github.com/first-tree-ai/context-tree",
"repository": "https://github.com/first-tree-ai/context-tree",
"license": "Apache-2.0",
"keywords": ["context-tree", "memory", "agents"],
"skills": "./skills/",
"interface": {
"displayName": "Context Tree",
"shortDescription": "Resolve and use durable project context",
"longDescription": "Link projects to verified Context Tree checkouts, then resolve, read, and publish durable context without persisting branches or credentials.",
"developerName": "First Tree AI",
"category": "Developer Tools",
"capabilities": ["Read", "Write"],
"websiteURL": "https://github.com/first-tree-ai/context-tree",
"defaultPrompt": [
"Link this project to its Context Tree.",
"Read the relevant Context Tree context.",
"Publish this durable decision to the Context Tree."
]
}
}
20 changes: 4 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,12 @@ jobs:
- run: pnpm check:package
- run: npm pack --dry-run

skill-discovery:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- name: Discover bundled skills with the pinned Agent Skills CLI
env:
DO_NOT_TRACK: "1"
run: npx --yes skills@1.5.19 add . --list

# Every push to main publishes a staging build under the `staging` dist-tag.
# `npm i @first-tree-ai/context-tree@staging` therefore always resolves to the
# newest build of main, and never to something older than the last stable.
publish-staging:
name: Publish staging package
needs: [test, skill-discovery]
needs: [test]
if: >-
github.repository == 'first-tree-ai/context-tree'
&& github.ref == 'refs/heads/main'
Expand Down Expand Up @@ -129,8 +117,8 @@ jobs:
if: steps.guard.outputs.publish == 'true'
run: |
npm version "${{ steps.resolve.outputs.version }}" --no-git-tag-version --allow-same-version
# tests/skills.test.ts (run by prepack) asserts every skill declares
# the package version, so the frontmatter has to move with it.
# Package tests assert every skill and plugin manifest declares the
# package version, so all published metadata has to move with it.
node scripts/sync-skill-versions.mjs

# Trusted publishing turns provenance on by default, but sigstore rejects
Expand All @@ -144,7 +132,7 @@ jobs:
# version. The tag is the source of truth; package.json is rewritten to match.
publish-release:
name: Publish production package
needs: [test, skill-discovery]
needs: [test]
if: >-
github.repository == 'first-tree-ai/context-tree'
&& github.event_name == 'push'
Expand Down
231 changes: 152 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,105 +1,178 @@
# Context Tree

`@first-tree-ai/context-tree` is the portable core for a GitHub-backed Context
Tree: durable decisions, constraints, and cross-domain relationships
stored as Markdown in a private GitHub repository. It ships deterministic local
scaffolding, validation, indexed reading, the canonical policy, Zod contracts,
and framework-neutral agent skills.

The core and CLI never make network requests or manage credentials. Init takes
an explicit GitHub `OWNER/REPO`. Read and write instead take an existing local
checkout whose exact path authorizes only that checkout and its verified,
credential-free GitHub `origin`. GitHub Enterprise Server and other forges are
unsupported.
`@first-tree-ai/context-tree` gives agents durable project context: decisions,
constraints, and relationships stored as Markdown in a private GitHub
repository. It supports Codex and Claude Code through a portable Agent Plugins
v1 package and includes a CLI for shell automation.

Each project is explicitly linked to a verified local checkout. Future sessions
resolve that checkout from the project's credential-free Git origin, or from its
real directory when the project is not a Git repository. Context Tree currently
supports repositories on GitHub.com only; GitHub Enterprise Server and other
forges are not supported.

## Install

Node.js 22.13 or newer and npm are required. Git is also required to initialize
trees and use Git-backed workflows.

### Codex or Claude Code plugin (recommended)

Install the marketplace and plugin, then start a new session so the host can
discover the skills and lifecycle hook.

For Codex:

```bash
pnpm add @first-tree-ai/context-tree
pnpm exec context-tree --help
codex plugin marketplace add first-tree-ai/context-tree
codex plugin add context-tree@context-tree
```

Or install the CLI globally:
For Claude Code:

```bash
claude plugin marketplace add first-tree-ai/context-tree
claude plugin install context-tree@context-tree
```

Marketplace installation requires repository access to
`first-tree-ai/context-tree`. These selectors resolve the npm `latest` package,
which must contain the plugin manifests, hook, four skills and launchers, and
`dist/cli/index.mjs`. Review and trust the session-start hook if your host asks.

The plugin uses its own packaged CLI, so plugin users do not need a global CLI
installation. Try asking:

> Link this project to my Context Tree, then read the relevant context.

> Publish this architectural decision to the Context Tree.

### Global CLI (optional)

Install the package globally only when scripts or terminal workflows need a
`context-tree` command on `PATH`:

```bash
npm install --global @first-tree-ai/context-tree
context-tree --help
```

Bundled skills can be installed with the Agent Skills CLI:
## CLI workflows

### Initialize or link a tree

Create a new tree and record a local link for the current project:

```bash
npx skills add first-tree-ai/context-tree --list
npx skills add first-tree-ai/context-tree --skill context-tree-read
context-tree init --repository acme/context --tree-path ./context-tree
```

## CLI
Or link a project to an existing, verified checkout:

The CLI exposes exactly four commands: `init`, `policy`, `read`, and `verify`.
Successful command results and runtime or argument failures emit one versioned
JSON object on stdout. Help and version output remain plain text.
```bash
context-tree link --project-path ./service --tree-path ./context-tree
```

If `init` omits `--tree-path`, it creates `./REPO`, using the repository name
verbatim as the directory and tree title. Scaffolding is create-only. It runs
ordinary `git init`, configures a credential-free GitHub origin, and creates a
validation workflow pinned to the package version and selected initial branch.
The init skill, rather than the CLI, owns the initial commit and any publication.

### Resolve, refresh, read, and verify

```bash
context-tree init \
--repository acme/context \
--tree-path ./context-tree
context-tree policy
context-tree verify --tree-path ./context-tree
context-tree resolve --project-path ./service
context-tree refresh --project-path ./service
context-tree read --tree-path ./context-tree
context-tree read product --tree-path ./context-tree
context-tree verify --tree-path ./context-tree
```

`resolve` checks the recorded checkout, origin, cleanliness, and root
`NODE.md`; it does not scan the whole semantic tree. `refresh` discovers the
live default branch, requires it to match the checked-out branch, and
fast-forwards before reads. Agent reads refresh and fully verify the tree, then
report the exact commit SHA. If GitHub is unavailable, a stale read requires
explicit authorization, is clearly labeled, and can never be used as a write
base.

Directory reads return the selected `NODE.md` body and metadata plus summaries
of immediate children. Leaf reads return the leaf body without children.

### Prepare and inspect a write

```bash
context-tree stage --project-path ./service
context-tree diff ./prepared-worktree --base HEAD
```

When `--tree-path` is omitted, init writes to `./REPO` and uses the `REPO`
segment verbatim as the tree title. Scaffolding is create-only and always
includes GitHub Actions validation pinned to the package version that created
the tree and filtered to the branch selected by ordinary `git init`. Init
requires Git and respects Git's effective `init.defaultBranch` configuration or
its compiled fallback. The CLI and library perform no GitHub or credential
operations. The init skill uses the CLI-created repository and current branch
for its local commit and, when GitHub CLI is authenticated, private-repository
publication and default-branch configuration.

Directory reads return that directory's `NODE.md` body and metadata plus
summaries of its immediate children. Leaf reads return the leaf body and no
children. Member classification is semantic metadata, not core access control.
The read skill fast-forward refreshes an explicitly
supplied existing checkout, requires it to be clean and on the expected branch,
derives `OWNER/REPO` from its safe GitHub origin, and reports the exact Git
commit SHA. If GitHub is unavailable, a stale read requires explicit
authorization and is clearly labeled; stale state can never become the base for
a write.

Writes are normal file edits performed by the write skill, not a CLI command.
Every write receives one concrete source through the authorized task context,
accepts an authoritative `default_branch`, freshly fetches that branch through
a supplied fetch-only checkout, creates an isolated worktree at its exact
commit, verifies the base, edits only necessary Markdown, verifies again,
inspects the complete diff, commits, and non-force pushes directly to the
supplied default branch. Concurrent updates are rebased and verified locally
with bounded retries. If direct publication is denied or the retry limit is
exhausted, the skill rebases against the latest default branch and opens a
conflict-free fallback PR without merging it or requesting reviewers. An
invalid base blocks semantic changes; an explicit repair request may produce a
repair-only write and commit limited to validator findings. Each write and
commit is scoped to one concrete source. Read and write use `agent_slug` solely
to select optional private memory at `members/<agent_slug>/memory.md`.

## Library integration

```ts
import { readContextTreePolicy, readTree, scaffoldTree, verifyTree } from "@first-tree-ai/context-tree";
import { contextTreeReadResultSchema, verifyTreeReportSchema } from "@first-tree-ai/context-tree/schemas";

scaffoldTree({
path: "./context-tree",
repository: "acme/context",
});
const verification = verifyTree("./context-tree");
const relevant = readTree("./context-tree", "systems");

verifyTreeReportSchema.parse(verification);
contextTreeReadResultSchema.parse(relevant);
`stage` fetches the live default branch and creates an isolated worktree at its
exact commit. After edits, `diff` reports all pending changes against the given
base (`HEAD` by default). These are preparation and inspection commands: there
is no CLI publish command. The write skill edits, verifies, reviews, commits,
rebases when necessary, and publishes the result.

### Retrieve the policy

```bash
context-tree policy
```

Git commit SHAs identify shared snapshots. Read nodes, child summaries, read results,
verification reports, and policy results intentionally contain no hashes or
digest fields. See [the format specification](docs/specification.md).
This returns the canonical policy packaged with the installed version.

## Command reference

| Command | Purpose | Essential arguments and options |
| --- | --- | --- |
| `link` | Link a project to a verified checkout | `--project-path <path>`, `--tree-path <path>` |
| `resolve` | Resolve a project's recorded link | `--project-path <path>` (default `.`) |
| `refresh` | Fast-forward a linked tree to its live default branch | `--project-path <path>` (default `.`) |
| `stage` | Prepare an isolated worktree for a write | `--project-path <path>` (default `.`) |
| `diff` | Inspect changes in a prepared worktree | `[tree-path]` (default `.`), `--base <ref>` (default `HEAD`) |
| `init` | Scaffold a new tree | `--repository <owner/repo>`, optional `--tree-path <path>` |
| `policy` | Print the packaged Context Tree policy | None |
| `read` | Read a node or Markdown leaf | `[path]` (default `.`), `--tree-path <path>` (default `.`) |
| `verify` | Validate tree structure and safety | `--tree-path <path>` (default `.`) |

Successful commands and runtime or argument failures emit one
`schemaVersion: 1` JSON object on stdout. Help and version output are plain
text. An invalid `verify` report is still emitted and exits with status 1. The
strict Zod schemas are the source of truth for public wire contracts.

Links are machine-local internal state in
`~/.context-tree/connections.json`; do not edit this file manually. Managed
clones default to `~/.context-tree/checkouts/OWNER/REPO`. Resolution does not
search for moved checkouts, so use the link skill again to repair a stale link.

## Safety and lifecycle

- **Credentials:** The core and CLI neither manage credentials nor perform
authenticated GitHub operations. Repository URLs containing credentials are
rejected and never logged; host Git and GitHub CLI own authentication.
- **Checkout validation:** Linking requires a clean, exact Git root with a safe
GitHub origin and a fully valid tree. Resolution fails closed for symlinks,
moved paths, dirty trees, origin mismatches, and invalid roots. `init` has a
narrow exception for its four new uncommitted scaffold files.
- **Git operations:** Reads fast-forward only. Writes start from a freshly
fetched default-branch commit in an isolated worktree and never force-push.
Commit SHAs identify shared snapshots.
- **Hooks:** Session and subagent hooks inject only a resolved tree identity and
path. They are silent when no link matches and never fetch, clone, or mutate.
They use only the plugin's packaged CLI and warn if it is unavailable.
- **Write fallback:** The write skill retries bounded concurrent updates. If a
direct push is denied or retries are exhausted, it opens a conflict-free PR
from the latest default branch without merging it or requesting reviewers.
Each write and commit is scoped to one concrete source.

For tree structure, link replacement rules, validation boundaries, memory
selection, read/write lifecycle details, and exact public contracts, see the
[Context Tree format specification](docs/specification.md).

## Compatibility

The root `plugin.json` is the portable Agent Plugins v1 manifest, and compatible
hosts discover the four skills from `skills/`. The Codex and Claude manifests
are current-client adapters for installation and lifecycle integration. Both
marketplaces install the same npm package, and all plugin components use its
private packaged CLI at the same version rather than a global `PATH` command.
Loading
Loading