Skip to content
Open
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
4 changes: 4 additions & 0 deletions .context/TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,10 @@ shipped.

### Misc

- [x] After PR #160 merges: rebase feat/opencode-mirror-sync onto main and open its PR (branch pushed to fork, stacked on #160) #session:45d47165 #branch:feat/opencode-mirror-sync #commit:e9e9139b #added:2026-08-28-183210

- [ ] Make the OpenCode MCP-config merge tolerate JSONC or fail loudly (currently a warning-level skip leaves a half-installed integration) #session:45d47165 #branch:feat/opencode-mirror-sync #commit:e9e9139b #added:2026-08-28-183210

- [ ] Full-site regen as standalone chore: make site with pinned zensical 0.0.51 rewrites 100+ pages with HTML-entity encoding differences (lib drift beneath the pin). Decide the canonical encoding, regenerate the whole site/ in one chore commit, and consider pinning zensical's dep tree (pipx runpip freeze) so future builds are reproducible. See LEARNINGS 2026-08-19 zensical-pin entry. #priority:medium #session:45d47165 #branch:feat/158-opencode-skill-parity #commit:f3f73875 #added:2026-08-19-221230

- [x] Regenerate site/ for docs/home/opencode.md (OpenCode skill parity, issue #158): zensical not installed on this machine, so make site could not run; run make site on a machine with the pinned zensical and commit the site/ churn #priority:medium #session:45d47165 #branch:feat/158-opencode-skill-parity #commit:ce5a8328 #added:2026-08-19-211552
Expand Down
41 changes: 32 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
clean all release build-all help \
test-coverage smoke site site-guard site-feed site-serve site-serve-lan site-setup audit check plugin-reload \
journal journal-serve journal-serve-lan gpg-fix gpg-test register-mcp reinstall check-tools \
sync-version check-version-sync sync-why check-why sync-copilot-skills check-copilot-skills sync-codex-skills check-codex-skills codex-plugin-install sync-opencode-skills check-opencode-skills sync-steering check-steering gemini-search \
sync-version check-version-sync sync-why check-why sync-copilot-skills check-copilot-skills sync-codex-skills check-codex-skills codex-plugin-install sync-opencode-skills check-opencode-skills sync-pi-skills check-pi-skills sync-steering check-steering gemini-search \
gitnexus-version gitnexus-update gitnexus-index gitnexus-mcp strip-gitnexus install-ctxctl reinstall-ctxctl

# Default binary name and output
Expand Down Expand Up @@ -42,7 +42,7 @@ sync-version:
echo "Plugin version synced to $$V"

## build: Build for current platform (syncs version + embedded docs + copilot/codex/opencode skills first)
build: sync-version sync-why sync-copilot-skills sync-codex-skills sync-opencode-skills
build: sync-version sync-why sync-copilot-skills sync-codex-skills sync-opencode-skills sync-pi-skills
CGO_ENABLED=0 go build -ldflags="-X github.com/ActiveMemory/ctx/internal/bootstrap.version=$$(cat VERSION | tr -d '[:space:]')" -o $(OUTPUT) ./cmd/ctx

## ctxctl: Build the maintainer-only ctxctl binary (audit channel) into dist/
Expand Down Expand Up @@ -183,6 +183,8 @@ audit:
@$(MAKE) --no-print-directory check-codex-skills
@echo "==> Checking OpenCode skills freshness..."
@$(MAKE) --no-print-directory check-opencode-skills
@echo "==> Checking Pi skills freshness..."
@$(MAKE) --no-print-directory check-pi-skills
@echo "==> Checking steering outputs freshness..."
@$(MAKE) --no-print-directory check-steering
@echo "==> Running tests..."
Expand Down Expand Up @@ -404,6 +406,27 @@ sync-copilot-skills:
sync-opencode-skills:
@./hack/sync-opencode-skills.sh

## sync-pi-skills: Mirror Pi skills from the generated OpenCode tree
# Depends on its producer: the Pi tree is a copy of the generated
# OpenCode tree, so the generator must finish first (make -j).
sync-pi-skills: sync-opencode-skills
@./hack/sync-pi-skills.sh

## check-pi-skills: Verify Pi skills mirror the OpenCode tree
check-pi-skills:
@TMPDIR=$$(mktemp -d) && \
cp -r internal/assets/integrations/pi/skills/ "$$TMPDIR/before" && \
./hack/sync-pi-skills.sh > /dev/null && \
if ! diff -rq "$$TMPDIR/before" internal/assets/integrations/pi/skills/ > /dev/null 2>&1; then \
echo "FAIL: Pi skills are stale — run 'make sync-pi-skills'"; \
diff -rq "$$TMPDIR/before" internal/assets/integrations/pi/skills/ || true; \
rm -rf internal/assets/integrations/pi/skills && cp -r "$$TMPDIR/before" internal/assets/integrations/pi/skills; \
rm -rf "$$TMPDIR"; \
exit 1; \
fi && \
rm -rf "$$TMPDIR" && \
echo "Pi skills are in sync."

## sync-steering: Regenerate tool-native steering outputs from .context/steering
sync-steering:
@CGO_ENABLED=0 go run ./cmd/ctx steering sync --all
Expand All @@ -429,8 +452,8 @@ check-copilot-skills:
cp -r "$$TMPDIR/before/"* internal/assets/integrations/copilot-cli/skills/; \
rm -rf "$$TMPDIR"; \
exit 1; \
fi; \
rm -rf "$$TMPDIR"; \
fi && \
rm -rf "$$TMPDIR" && \
echo "Copilot CLI skills are in sync."

## sync-codex-skills: Sync Codex plugin skills from canonical ctx skills
Expand All @@ -456,8 +479,8 @@ check-codex-skills:
cp "$$TMPDIR/plugin.json" internal/assets/claude/.codex-plugin/plugin.json; \
rm -rf "$$TMPDIR"; \
exit 1; \
fi; \
rm -rf "$$TMPDIR"; \
fi && \
rm -rf "$$TMPDIR" && \
echo "Codex skills are in sync."

## codex-plugin-install: Register this checkout as a Codex marketplace and install the ctx plugin
Expand All @@ -473,11 +496,11 @@ check-opencode-skills:
if ! diff -rq "$$TMPDIR/before" internal/assets/integrations/opencode/skills/ > /dev/null 2>&1; then \
echo "FAIL: OpenCode skills are stale — run 'make sync-opencode-skills'"; \
diff -rq "$$TMPDIR/before" internal/assets/integrations/opencode/skills/ || true; \
cp -r "$$TMPDIR/before/"* internal/assets/integrations/opencode/skills/; \
rm -rf internal/assets/integrations/opencode/skills && cp -r "$$TMPDIR/before" internal/assets/integrations/opencode/skills; \
rm -rf "$$TMPDIR"; \
exit 1; \
fi; \
rm -rf "$$TMPDIR"; \
fi && \
rm -rf "$$TMPDIR" && \
echo "OpenCode skills are in sync."

## check-why: Verify embedded why docs match source docs
Expand Down
18 changes: 12 additions & 6 deletions docs/home/opencode.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ This does two things:
| `.opencode/plugins/ctx.ts` | Lifecycle plugin (hooks into `ctx system` commands) |
| `~/.config/opencode/opencode.json` | Global MCP server registration (or `$OPENCODE_HOME/opencode.json`) |
| `AGENTS.md` | Agent instructions (OpenCode reads this natively) |
| `.opencode/skills/ctx-*/SKILL.md` | Slash command skills |
| `.opencode/skills/ctx-*/SKILL.md` | Slash command skills (plus each skill's `references/` files) |

The plugin is a single file with no runtime dependencies; no `bun install`
or `npm install` needed. OpenCode loads it automatically on launch.
Expand Down Expand Up @@ -112,11 +112,17 @@ unnecessary.

## Slash Commands

The skills are generated from the canonical ctx skill tree at build
time, so their names and behavior match the Claude Code integration
one-to-one.

Session lifecycle:
The full canonical ctx skill tree ships as OpenCode skills, generated
at build time (`hack/sync-opencode-skills.sh` strips the Claude-only
`allowed-tools:` frontmatter), so skill names and behavior match the
Claude Code integration one-to-one. Four skills are Claude Code-only
and are not shipped: `ctx-permission-sanitize` (audits
`.claude/settings.local.json`), `ctx-plan-import` (reads
`~/.claude/plans/`), `ctx-dream` (headless `claude -p` cron), and
`ctx-skill-create` (authors Claude Code skills). Skills that cite
`references/` files ship those files alongside `SKILL.md`.

The ones you'll reach for most, by workflow. Session lifecycle:

| Command | When to use |
|---------|-------------|
Expand Down
11 changes: 10 additions & 1 deletion docs/home/pi.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,16 @@ the Pi integration.

## Skills

The bundled skills are available as `/skill:*` commands:
Pi ships the same bundled skill set as OpenCode, generated at build time
from the canonical ctx skills (`hack/sync-pi-skills.sh` copies the
generated OpenCode tree). Four skills are Claude Code-only and are not
shipped: `ctx-permission-sanitize` (audits
`.claude/settings.local.json`), `ctx-plan-import` (reads
`~/.claude/plans/`), `ctx-dream` (headless `claude -p` cron), and
`ctx-skill-create` (authors Claude Code skills). Skills that cite
`references/` files ship those files alongside `SKILL.md`.

The ones you'll reach for most, available as `/skill:*` commands:

| Command | When to use |
|---------|-------------|
Expand Down
7 changes: 6 additions & 1 deletion hack/sync-codex-skills.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

CTX_SKILLS="internal/assets/claude/skills"
CODEX_SKILLS="internal/assets/codex/skills"

Expand All @@ -34,7 +37,9 @@ EXCLUDE=(

excluded() {
local name="$1"
for x in "${EXCLUDE[@]}"; do
# Guard the expansion: bash 3.2 under set -u aborts on an empty
# array; see the lint-drift.sh guard and LEARNINGS 2026-08-19.
for x in ${EXCLUDE[@]+"${EXCLUDE[@]}"}; do
[ "$x" = "$name" ] && return 0
done
return 1
Expand Down
66 changes: 55 additions & 11 deletions hack/sync-opencode-skills.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,76 @@
# generated from them with the `allowed-tools` frontmatter key stripped
# (Claude Code-specific, not applicable to OpenCode).
#
# Enrollment is opt-in by directory presence: a skill syncs iff its
# directory exists under the OpenCode tree. Skills that exist only in
# the OpenCode directory (no ctx counterpart) are left untouched.
# Like the Codex sync (and unlike the Copilot sync), this is a full
# mirror: every ctx skill that is not on the exclusion list below is
# (re)generated, and OpenCode skill directories whose ctx counterpart
# disappeared are removed. The exclusion list names skills whose body
# only makes sense inside Claude Code (its settings files, plan files,
# or headless runner).

set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

CTX_SKILLS="internal/assets/claude/skills"
OPENCODE_SKILLS="internal/assets/integrations/opencode/skills"

# Claude-only skills: operate on Claude Code-specific state.
EXCLUDE=(
ctx-permission-sanitize # audits .claude/settings.local.json
ctx-plan-import # imports ~/.claude/plans/
ctx-dream # headless `claude -p` cron + guard.sh
ctx-skill-create # authors Claude Code skills/plugins
)

excluded() {
local name="$1"
# Guard the expansion: bash 3.2 under set -u aborts on an empty
# array; see the lint-drift.sh guard and LEARNINGS 2026-08-19.
for x in ${EXCLUDE[@]+"${EXCLUDE[@]}"}; do
[ "$x" = "$name" ] && return 0
done
return 1
}

mkdir -p "$OPENCODE_SKILLS"

synced=0
removed=0
skipped=0

for opencode_dir in "$OPENCODE_SKILLS"/*/; do
skill_name=$(basename "$opencode_dir")
ctx_skill="$CTX_SKILLS/$skill_name/SKILL.md"
opencode_skill="$opencode_dir/SKILL.md"
for ctx_dir in "$CTX_SKILLS"/*/; do
skill_name=$(basename "$ctx_dir")
ctx_skill="$ctx_dir/SKILL.md"
[ -f "$ctx_skill" ] || continue

if [ ! -f "$ctx_skill" ]; then
# No ctx counterpart — OpenCode-only skill, leave untouched.
if excluded "$skill_name"; then
skipped=$((skipped + 1))
continue
fi

mkdir -p "$OPENCODE_SKILLS/$skill_name"
# Strip `allowed-tools:` line from frontmatter (Claude Code-specific).
sed '/^allowed-tools:/d' "$ctx_skill" > "$opencode_skill"
sed '/^allowed-tools:/d' "$ctx_skill" > "$OPENCODE_SKILLS/$skill_name/SKILL.md"

# Mirror the skill's references/ directory (skill bodies cite these
# files; shipping SKILL.md alone would point agents at 404s).
rm -rf "$OPENCODE_SKILLS/$skill_name/references"
if [ -d "$ctx_dir/references" ]; then
cp -R "$ctx_dir/references" "$OPENCODE_SKILLS/$skill_name/references"
fi
synced=$((synced + 1))
done

echo "OpenCode skills synced: $synced updated, $skipped OpenCode-only (unchanged)."
# Remove OpenCode skills whose ctx counterpart is gone or now excluded.
for opencode_dir in "$OPENCODE_SKILLS"/*/; do
[ -d "$opencode_dir" ] || continue
skill_name=$(basename "$opencode_dir")
if [ ! -f "$CTX_SKILLS/$skill_name/SKILL.md" ] || excluded "$skill_name"; then
rm -rf "$opencode_dir"
removed=$((removed + 1))
fi
done

echo "OpenCode skills synced: $synced updated, $skipped Claude-only (excluded), $removed removed."
41 changes: 41 additions & 0 deletions hack/sync-pi-skills.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

# / ctx: https://ctx.ist
# ,'`./ do you remember?
# `.,'\
# \ Copyright 2026-present Context contributors.
# SPDX-License-Identifier: Apache-2.0

# sync-pi-skills.sh — sync Pi skills from the generated OpenCode tree.
#
# specs/pi-cli-integration.md defines the Pi skill set as "the same
# bundled skill set as OpenCode", and TestPiSkillsMirrorOpenCode
# freezes the two trees byte-for-byte. This script makes that
# derivation structural: the Pi tree is a verbatim copy of the
# generated OpenCode tree (SKILL.md files and their references/
# directories), so the freeze can never be broken by a one-sided
# edit.
#
# Run order matters: hack/sync-opencode-skills.sh regenerates the
# OpenCode tree from the canonical ctx skills first; `make build`
# and `make audit` sequence them correctly.

set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

OPENCODE_SKILLS="internal/assets/integrations/opencode/skills"
PI_SKILLS="internal/assets/integrations/pi/skills"

if [ ! -d "$OPENCODE_SKILLS" ]; then
echo "FAIL: $OPENCODE_SKILLS not found — run sync-opencode-skills first" >&2
exit 1
fi

rm -rf "$PI_SKILLS"
mkdir -p "$(dirname "$PI_SKILLS")"
cp -R "$OPENCODE_SKILLS" "$PI_SKILLS"

count=$(find "$PI_SKILLS" -name SKILL.md | wc -l | tr -d ' ')
echo "Pi skills synced: $count mirrored from the OpenCode tree."
2 changes: 2 additions & 0 deletions internal/assets/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import (
//go:embed integrations/copilot-cli/skills/*/SKILL.md
//go:embed integrations/opencode/plugin/index.ts
//go:embed integrations/opencode/skills/*/SKILL.md
//go:embed integrations/opencode/skills/*/references/*
//go:embed integrations/pi/extension/ctx.ts
//go:embed integrations/pi/skills/*/SKILL.md
//go:embed integrations/pi/skills/*/references/*
//go:embed hooks/messages/*/*.txt hooks/messages/registry.yaml hooks/trace/*.sh
//go:embed schema/*.json why/*.md
//go:embed permissions/*.txt commands/*.yaml commands/text/*.yaml journal/*.css
Expand Down
Loading
Loading