diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..c9568d6 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,18 @@ +{ + "name": "terraphim-skills", + "description": "Public Community skills from Terraphim AI.", + "owner": { + "name": "Terraphim AI", + "email": "engineering@terraphim.ai" + }, + "plugins": [ + { + "name": "terraphim-skills-intro", + "source": "./", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "version": "0.2.0", + "category": "development", + "homepage": "https://terraphim-skills.md/" + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..17c3605 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "terraphim-skills-intro", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "version": "0.2.0", + "author": { + "name": "Terraphim AI", + "email": "engineering@terraphim.ai" + }, + "homepage": "https://terraphim-skills.md/", + "repository": "https://github.com/terraphim/terraphim-cursor-plugin", + "license": "Apache-2.0", + "keywords": [ + "terraphim", + "code-search", + "learning", + "memory", + "knowledge-graph", + "developer-tools" + ] +} diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index ab8199f..dab9cf6 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "terraphim-skills-intro", "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", - "version": "0.1.0", + "version": "0.2.0", "author": { "name": "Terraphim AI", "email": "engineering@terraphim.ai" @@ -9,7 +9,6 @@ "homepage": "https://terraphim-skills.md/", "repository": "https://github.com/terraphim/terraphim-cursor-plugin", "license": "Apache-2.0", - "logo": "assets/logo.svg", "keywords": [ "terraphim", "code-search", @@ -18,6 +17,7 @@ "knowledge-graph", "developer-tools" ], + "logo": "assets/logo.svg", "skills": [ "skills/terraphim-grep", "skills/terraphim-agent-learn", diff --git a/.github/trusted-release-signers b/.github/trusted-release-signers new file mode 100644 index 0000000..5e7c4b7 --- /dev/null +++ b/.github/trusted-release-signers @@ -0,0 +1 @@ +alex@metacortex.engineer namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICRY4s+NewIgKEE/fgGCtIF0Kd9Q9y6pELMuY+xM2mLC diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..43a5efb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,69 @@ +name: Publish marketplace pack + +on: + push: + tags: + - "v*" + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Check out tagged source + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: "3.12" + + - name: Validate tagged pack + run: | + expected_tag="v$(python3 scripts/generate_distribution.py --print-version)" + test "$GITHUB_REF_NAME" = "$expected_tag" + git config gpg.format ssh + git config gpg.ssh.allowedSignersFile \ + "$GITHUB_WORKSPACE/.github/trusted-release-signers" + git verify-tag "$GITHUB_REF_NAME" + python3 scripts/generate_distribution.py --check + python3 -m unittest discover -s tests -p 'test_*.py' + + - name: Rebuild and compare AutoClaw archives + run: | + output="$(mktemp -d)" + python3 scripts/generate_distribution.py --autoclaw-dist "$output" + diff -u dist/autoclaw/SHA256SUMS "$output/SHA256SUMS" + for archive in dist/autoclaw/*.zip; do + name="$(basename "$archive")" + cmp "$archive" "$output/$name" + done + + publish: + needs: validate + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out validated tagged source + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + persist-credentials: false + + - name: Publish immutable release assets + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "$GITHUB_REF_NAME" \ + dist/autoclaw/*.zip \ + dist/autoclaw/SHA256SUMS \ + assets/v-model-overview.svg \ + assets/v-model-overview.png \ + --repo "$GITHUB_REPOSITORY" \ + --title "Terraphim Skills Introduction $GITHUB_REF_NAME" \ + --generate-notes \ + --verify-tag diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..179f6dd --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,39 @@ +name: Validate public marketplace pack + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: "3.12" + + - name: Check generated manifests + run: python3 scripts/generate_distribution.py --check + + - name: Run tests + run: python3 -m unittest discover -s tests -p 'test_*.py' + + - name: Verify reproducible AutoClaw archives + run: | + output="$(mktemp -d)" + python3 scripts/generate_distribution.py --autoclaw-dist "$output" + diff -u dist/autoclaw/SHA256SUMS "$output/SHA256SUMS" + + - name: Reject whitespace errors + run: git diff --check diff --git a/.zcode-plugin/plugin.json b/.zcode-plugin/plugin.json new file mode 100644 index 0000000..82087fa --- /dev/null +++ b/.zcode-plugin/plugin.json @@ -0,0 +1,30 @@ +{ + "name": "terraphim-skills-intro", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "version": "0.2.0", + "author": { + "name": "Terraphim AI", + "email": "engineering@terraphim.ai" + }, + "homepage": "https://terraphim-skills.md/", + "repository": "https://github.com/terraphim/terraphim-cursor-plugin", + "license": "Apache-2.0", + "keywords": [ + "terraphim", + "code-search", + "learning", + "memory", + "knowledge-graph", + "developer-tools" + ], + "displayName": "Terraphim Skills Introduction", + "description_i18n": { + "en": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "zh-CN": "使用 Terraphim 命令行工具搜索代码、记录经验并检索记忆。" + }, + "skills": [ + "./skills/terraphim-grep", + "./skills/terraphim-agent-learn", + "./skills/terraphim-agent-memory" + ] +} diff --git a/NOTICE b/NOTICE index 088550c..f0e4833 100644 --- a/NOTICE +++ b/NOTICE @@ -1,2 +1,5 @@ Terraphim Skills Introduction for Cursor Copyright 2026 Terraphim AI + +The V-model overview artwork in assets/ is Copyright 2026 Terraphim AI and is +distributed under the Apache License 2.0 with the rest of this repository. diff --git a/README.md b/README.md index c2d964c..9d737f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# Terraphim Skills Introduction for Cursor +# Terraphim Skills Introduction -Three small, open-source skills introduce Cursor users to Terraphim's local code search, operational learning, and agentic memory commands. +Three small, open-source skills bring Terraphim's local code search, operational +learning, and agent memory workflows to Cursor, Kimi Code, AutoClaw, ZCode, +Hermes Agent, skills.sh, and Claude Code. | Skill | Command family | Purpose | |---|---|---| @@ -8,38 +10,67 @@ Three small, open-source skills introduce Cursor users to Terraphim's local code | `terraphim-agent-learn` | `terraphim-agent learn` | Inspect failures and capture verified operational corrections. | | `terraphim-agent-memory` | `terraphim-agent memory` | Retrieve role-scoped memory, inspect provenance, and govern its lifecycle. | -These are independently written Apache-2.0 command wrappers. They do not contain or redistribute the proprietary Terraphim Skills catalogue. +These Apache-2.0 command wrappers do not bundle executables, secrets, hooks, or +proprietary skill content. They remain useful without a marketplace account. -## Prerequisites +## Install the command dependencies -Install current Terraphim command-line tools using the release instructions at , then verify the installed surface: +On macOS or Linux with Homebrew: ```bash +brew tap terraphim/terraphim +brew install terraphim-grep terraphim-agent terraphim-grep --version terraphim-agent --version terraphim-agent learn --help terraphim-agent memory --help ``` -The wrappers inspect `--help` at runtime so they remain honest about the locally installed version. +The formulae install the signed, checksummed Terraphim Clients v1.21.14 release. +See [dependency installation](docs/install-dependencies.md) for updates, removal, +non-Homebrew installation, signature checks, and PATH troubleshooting. The skills +never install dependencies automatically. + +## Install in your agent + +| Host | Installation | +|---|---| +| Cursor | Already submitted; install from Cursor Marketplace, or use the local-copy instructions below. | +| Kimi Code | Install this repository or add `marketplaces/kimi.json` as a custom marketplace. | +| AutoClaw | Import one checksummed ZIP per skill with **Skills & Connectors → Skills → Create → Add skill file**. | +| ZCode | Add `marketplaces/zcode.json` as a personal marketplace and install `terraphim-skills-intro`; curated listing is a separate maintainer-reviewed PR. | +| Hermes Agent | Add `terraphim/terraphim-cursor-plugin` as a tap, then inspect and install the three skills. | +| skills.sh | Run `npx skills add terraphim/terraphim-cursor-plugin`; use `DISABLE_TELEMETRY=1` to opt out of anonymous telemetry. | +| Claude Code | Add the repository as a marketplace, then install the plugin as shown below. | + +Claude Code commands: + +```text +claude plugin marketplace add terraphim/terraphim-cursor-plugin +claude plugin install terraphim-skills-intro@terraphim-skills +``` + +Availability in a host's curated public marketplace is separate from direct or +custom installation. See the [distribution guide](docs/distribution.md) for exact +install, update, discovery, and removal steps and current publication status. ## Local Cursor installation -For local development, copy this repository into Cursor's local plugin directory: +For local development, copy this repository into: ```text ~/.cursor/plugins/local/terraphim-skills-intro ``` Cursor 3.20 rejects a symlink when its resolved target is outside -`~/.cursor/plugins/local`, so use a real directory for a reliable test. For example: +`~/.cursor/plugins/local`, so use a real directory: ```sh cp -R /path/to/terraphim-cursor-plugin \ ~/.cursor/plugins/local/terraphim-skills-intro ``` -Reload Cursor, open **Customize**, and confirm that all three skills appear. Invoke them by name or ask Cursor to search code, inspect an earlier command failure, or retrieve project memory. +Reload Cursor, open **Customize**, and confirm that all three skills appear. ## Example requests @@ -47,16 +78,23 @@ Reload Cursor, open **Customize**, and confirm that all three skills appear. Inv - “Search project learnings for an earlier failed deployment command.” - “Retrieve role-scoped memory about OAuth redirect validation and show its provenance.” -The skills default to local, read-only operations. Persistent learning or memory changes remain explicit and scoped. +The skills default to local, read-only operations. Persistent learning or memory +changes remain explicit and scoped. Review [permissions and side effects](docs/permissions.md) +before enabling writes or configured model synthesis. -## Terraphim Skills +## Continue with Terraphim Skills -Browse the Terraphim catalogue and non-technical guidance at . This introductory plugin remains useful on its own and requires no marketplace account. +Browse the [Community, Core, and Premium catalogue](https://terraphim-skills.md/skills/). +The public introduction contains no proprietary instructions or entitlement token. +Following a related-skill link never creates a checkout or transaction. Access and +purchase decisions remain on Terraphim's authenticated site and MCP services. ## Development ```bash +python3 scripts/generate_distribution.py --check python3 -m unittest discover -s tests -p 'test_*.py' +python3 scripts/generate_distribution.py --autoclaw-dist dist/autoclaw ``` ## Licence diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..b655a07 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,55 @@ +# Terraphim Skills Introduction + +本插件提供三个开源技能,让 Kimi Code、ZCode 及其他智能体能够使用 +Terraphim 的本地代码搜索、经验学习和智能体记忆工作流。 + +## 技能 + +- `terraphim-grep`:在本地代码和文档中进行有界搜索,默认离线。 +- `terraphim-agent-learn`:检查失败并记录经过验证的操作修正。 +- `terraphim-agent-memory`:检索角色范围内的记忆并检查来源。 + +这些技能采用 Apache-2.0 许可证,不包含可执行文件、密钥、后台任务或 +Terraphim 专有技能内容。 + +## 安装依赖 + +在 macOS 或安装了 Homebrew 的 Linux 上运行: + +```bash +brew tap terraphim/terraphim +brew install terraphim-grep terraphim-agent +terraphim-grep --version +terraphim-agent --version +terraphim-agent learn --help +terraphim-agent memory --help +``` + +技能不会自动安装软件。没有 Homebrew 时,请从 +[Terraphim Clients v1.21.14](https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.14) +下载适合平台的文件,并用 `SHA256SUMS` 验证。 + +## 安装与使用 + +在 ZCode 的“发现”页面把仓库内的 `marketplaces/zcode.json` 添加为个人市场, +然后安装 `terraphim-skills-intro`。进入官方精选市场仍需由维护者审核并合并 +单独的 Pull Request。各平台的安装、更新和卸载步骤见 +[分发指南](docs/distribution.md)。 + +示例请求: + +- “使用 Terraphim Grep 查找授权回调并显示两行上下文。” +- “搜索项目经验,找出之前失败的部署命令。” +- “检索有关 OAuth 重定向验证的角色记忆,并显示其来源。” + +默认操作是本地且只读的。写入学习或记忆必须获得明确授权;启用模型综合 +前必须确认数据边界和可能的费用。 + +浏览 [Community、Core 和 Premium 技能目录](https://terraphim-skills.md/skills/)。 +此链接只提供信息,不会自动创建结账、付款或交易。 + +隐私政策: + +服务条款: + +许可证:Apache-2.0 diff --git a/assets/v-model-overview.png b/assets/v-model-overview.png new file mode 100644 index 0000000..2f2a295 Binary files /dev/null and b/assets/v-model-overview.png differ diff --git a/assets/v-model-overview.svg b/assets/v-model-overview.svg new file mode 100644 index 0000000..d59f209 --- /dev/null +++ b/assets/v-model-overview.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + The V-Model: Architecture of Discipline + + LEFT SIDE + Planning + RIGHT SIDE + Testing + + + + + + + validates + + + verifies + + + + EXPLORE + + + ELIMINATE + + + EXECUTE + + + + + + VERIFY + + + VALIDATE + + + + + Phase 1: Research + Problem understanding + Constraints & risks + Success criteria + + + + + + Phase 5: Validation + System testing + UAT with stakeholders + Formal sign-off + + + + + + Phase 2: Design + File changes + API signatures + Test strategy + Document NOT-doing + + + + + + Phase 4: Verification + Unit testing + Integration testing + Traceability matrix + Test execution + + + + + + Phase 2.5 + Specification + Deep interview + Edge cases + Tradeoffs + + + + + + Quality + Gate + Code review + UBS & security + Traceability + + + + + + Phase 3: Implementation + Test first | Small commits | Quality checks + + + + DEFECT LOOP-BACK + Defects trace back to the originating left-side phase + diff --git a/dist/autoclaw/SHA256SUMS b/dist/autoclaw/SHA256SUMS new file mode 100644 index 0000000..24c9734 --- /dev/null +++ b/dist/autoclaw/SHA256SUMS @@ -0,0 +1,3 @@ +38d8f394d04aeec419cc52a1d146525b8357bc48df5b03b0f24970e5b37453d9 terraphim-grep-0.2.0.zip +69c2be81b8ff879fc7f9a62f5d48399be98e9a9934f3b17e2fcd657729590012 terraphim-agent-learn-0.2.0.zip +b0f9de6fa5eff647b92bd6a6aeabe825ed3f7e00d1f690ae4f0145a7489357e9 terraphim-agent-memory-0.2.0.zip diff --git a/dist/autoclaw/terraphim-agent-learn-0.2.0.zip b/dist/autoclaw/terraphim-agent-learn-0.2.0.zip new file mode 100644 index 0000000..7e2b0e9 Binary files /dev/null and b/dist/autoclaw/terraphim-agent-learn-0.2.0.zip differ diff --git a/dist/autoclaw/terraphim-agent-memory-0.2.0.zip b/dist/autoclaw/terraphim-agent-memory-0.2.0.zip new file mode 100644 index 0000000..adc4533 Binary files /dev/null and b/dist/autoclaw/terraphim-agent-memory-0.2.0.zip differ diff --git a/dist/autoclaw/terraphim-grep-0.2.0.zip b/dist/autoclaw/terraphim-grep-0.2.0.zip new file mode 100644 index 0000000..97d7917 Binary files /dev/null and b/dist/autoclaw/terraphim-grep-0.2.0.zip differ diff --git a/distribution/metadata.json b/distribution/metadata.json new file mode 100644 index 0000000..8b7a809 --- /dev/null +++ b/distribution/metadata.json @@ -0,0 +1,59 @@ +{ + "schema_version": 1, + "plugin": { + "name": "terraphim-skills-intro", + "display_name": "Terraphim Skills Introduction", + "version": "0.2.0", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "description_zh_cn": "使用 Terraphim 命令行工具搜索代码、记录经验并检索记忆。", + "author_name": "Terraphim AI", + "author_email": "engineering@terraphim.ai", + "homepage": "https://terraphim-skills.md/", + "catalogue": "https://terraphim-skills.md/skills/", + "repository": "https://github.com/terraphim/terraphim-cursor-plugin", + "license": "Apache-2.0", + "category": "developer-tools", + "keywords": [ + "terraphim", + "code-search", + "learning", + "memory", + "knowledge-graph", + "developer-tools" + ] + }, + "runtime": { + "tap": "terraphim/terraphim", + "release": "https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.14", + "formulae": [ + "terraphim-grep", + "terraphim-agent" + ], + "verify": [ + "terraphim-grep --version", + "terraphim-agent --version", + "terraphim-agent learn --help", + "terraphim-agent memory --help" + ] + }, + "skills": [ + { + "name": "terraphim-grep", + "path": "skills/terraphim-grep", + "command": "terraphim-grep", + "mode": "read-only-by-default" + }, + { + "name": "terraphim-agent-learn", + "path": "skills/terraphim-agent-learn", + "command": "terraphim-agent learn", + "mode": "explicit-writes" + }, + { + "name": "terraphim-agent-memory", + "path": "skills/terraphim-agent-memory", + "command": "terraphim-agent memory", + "mode": "explicit-writes" + } + ] +} diff --git a/docs/distribution.md b/docs/distribution.md new file mode 100644 index 0000000..10b0846 --- /dev/null +++ b/docs/distribution.md @@ -0,0 +1,94 @@ +# Multi-marketplace distribution + +This repository is the canonical source for all hosts. Release `v0.2.0` contains +exactly three skills and deterministic AutoClaw archives. + +## Availability model + +- **Direct/custom install** is controlled by the user and available from the + immutable GitHub release. +- **Curated marketplace listing** is controlled by each marketplace maintainer and + remains pending until that marketplace confirms indexing or approval. +- Cursor is already submitted and is a regression target, not a new submission. +- AutoClaw local ZIP import is supported. ZhipuAI Skills Center inclusion is a + separate external review; ClawHub is not treated as proof of that inclusion. + +## Kimi Code + +Install the immutable release URL through Kimi Code's `/plugins install`, or +open `/plugins marketplace` with +`https://raw.githubusercontent.com/terraphim/terraphim-cursor-plugin/v0.2.0/marketplaces/kimi.json` +and install +`terraphim-skills-intro`. Run `/plugins reload` (or start a new session), then +confirm that exactly the three documented skills appear. The native manifest is +`kimi.plugin.json`; root `plugin.json` provides compatibility with Kimi CLI +releases whose shell-level `kimi plugin install` command expects that filename. +Update by installing the newer tag; remove through Kimi's plugin manager. + +## AutoClaw + +Download the three ZIP files and `SHA256SUMS` from the `v0.2.0` release. Verify +each digest, then use **Skills & Connectors → Skills → Create → Add skill file**. +Import each ZIP separately. Restart AutoClaw and confirm the skills persist. Remove +them through the same Skills screen. If Homebrew binaries are missing from the GUI +`PATH`, restart AutoClaw after installing the dependencies. + +## ZCode + +Open ZCode's **Discover** view and add +`https://raw.githubusercontent.com/terraphim/terraphim-cursor-plugin/v0.2.0/marketplaces/zcode.json` +as a personal marketplace source, install `terraphim-skills-intro`, then confirm the Plugin +Skills view shows exactly three skills. Curated discovery requires a separate +pull request to `zai-org/zcode-plugins`; this repository does not claim that +acceptance before the maintainers merge it. Update or remove the installed +plugin through ZCode's plugin manager. + +## Hermes Agent + +Add the repository as a GitHub tap, then inspect each skill before installing: + +```bash +hermes skills tap add terraphim/terraphim-cursor-plugin +hermes skills inspect terraphim/terraphim-cursor-plugin/skills/terraphim-grep +hermes skills inspect terraphim/terraphim-cursor-plugin/skills/terraphim-agent-learn +hermes skills inspect terraphim/terraphim-cursor-plugin/skills/terraphim-agent-memory +``` + +Record the immutable `v0.2.0` provenance. Remove the skills with Hermes' normal +skill-management command. + +## skills.sh + +Use an isolated agent target and run: + +```bash +npx skills add terraphim/terraphim-cursor-plugin +``` + +Set `DISABLE_TELEMETRY=1` to opt out of anonymous telemetry. Confirm exactly three +skills are offered and that their files match tag `v0.2.0`. Update by repeating the +command for the new tag; remove the installed skill directories through the target +agent's documented skill manager. + +## Claude Code + +```text +claude plugin marketplace add terraphim/terraphim-cursor-plugin +claude plugin install terraphim-skills-intro@terraphim-skills +``` + +Run `claude plugin validate --strict .` before release. Use `claude plugin list` +to verify the installed version and normal Claude plugin commands to update or +remove it. + +## Cursor + +Install from Cursor Marketplace. For local testing, follow the real-directory +copy instructions in the README; Cursor 3.20 rejects external symlink targets. + +## Catalogue boundary + +Each host links to . Community skills are +freely obtainable; Core and Premium content follows the catalogue's entitlement +rules. Public packages never embed proprietary bodies, tokens, checkout URLs, or +automatic transactions. diff --git a/docs/install-dependencies.md b/docs/install-dependencies.md new file mode 100644 index 0000000..aafdf44 --- /dev/null +++ b/docs/install-dependencies.md @@ -0,0 +1,58 @@ +# Install Terraphim command dependencies + +The three skills are workflow instructions. They call two local binaries and never +install software automatically. + +## Homebrew installation + +On macOS or Linux with Homebrew: + +```bash +brew tap terraphim/terraphim +brew install terraphim-grep terraphim-agent +terraphim-grep --version +terraphim-agent --version +terraphim-agent learn --help +terraphim-agent memory --help +``` + +The formulae use immutable, signed and checksummed v1.21.14 archives. If both +binaries already pass the four probes, do not reinstall them. + +## Update + +```bash +brew update +brew upgrade terraphim-grep terraphim-agent +``` + +Run the four probes again after upgrading. The installed `--help` output is the +authority for available options. + +## Remove + +```bash +brew uninstall terraphim-grep terraphim-agent +brew untap terraphim/terraphim +``` + +Removing the binaries does not remove learning or memory data. Review local data +locations before deleting user-created state. + +## Without Homebrew + +Download the correct archive and `SHA256SUMS` from the +[v1.21.14 release](https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.14). +Verify the archive checksum before extracting it. macOS archives are signed and +notarized; do not bypass Gatekeeper. Linux archives are signed through the release +checksum and signature chain. + +## Troubleshooting + +- If a host cannot resolve a binary, restart it after installation so it receives + the current `PATH`. +- Homebrew usually installs to `/opt/homebrew/bin` on Apple Silicon, + `/usr/local/bin` on Intel macOS, and `/home/linuxbrew/.linuxbrew/bin` on Linux. +- Do not copy credentials or private memory into diagnostics. +- Do not use `xattr` or Gatekeeper-bypass commands. Verify the official archive + and report a signature failure instead. diff --git a/docs/marketplace-submission-pack.md b/docs/marketplace-submission-pack.md new file mode 100644 index 0000000..b1dd09e --- /dev/null +++ b/docs/marketplace-submission-pack.md @@ -0,0 +1,120 @@ +# Terraphim Skills Introduction — marketplace submission pack + +This document is the reusable, public submission collateral for the Terraphim +introductory skills plugin. Platform-specific manifests are generated from +`distribution/metadata.json`; this copy should remain consistent with that +canonical source. + +## Listing identity + +- **Name:** Terraphim Skills Introduction +- **Slug:** `terraphim-skills-intro` +- **Publisher:** Terraphim AI +- **Category:** Developer tools +- **Licence:** Apache-2.0 +- **Homepage:** +- **Public catalogue:** +- **Repository:** + +### Tagline + +Search code, capture learning, and retrieve memory with Terraphim command-line +tools. + +### Short description + +Three Community skills introduce local code search, structured learning +capture, and reusable memory. The skills run Terraphim's local command-line +tools and explain every write before it happens. + +### Long description + +Terraphim Skills Introduction gives coding agents three focused, open-source +workflows: + +1. `terraphim-grep` searches local code and documentation with context. +2. `terraphim-agent-learn` turns an explicit lesson into a reusable local + knowledge entry. +3. `terraphim-agent-memory` retrieves, records, and applies local project + memory. + +The plugin contains instructions, not bundled executables. Users install the +signed Terraphim binaries through Homebrew and can verify both tools before an +agent uses them. Search is read-only by default. Learning and memory writes are +performed only when the user asks for them. + +The Community skills stand on their own. They also link neutrally to the +Terraphim Skills catalogue, where users can discover Community, Core, and +Premium workflows without an in-skill checkout or purchase prompt. + +## Suggested prompts + +- “Use Terraphim Grep to find where OAuth callback state is validated.” +- “Capture what we learned from this incident for the next session.” +- “Search project memory for the deployment constraints, then cite the source.” + +## Runtime prerequisites + +```sh +brew tap terraphim/terraphim +brew install terraphim-grep terraphim-agent +terraphim-grep --version +terraphim-agent --version +terraphim-agent learn --help +terraphim-agent memory --help +``` + +See [Install dependencies](install-dependencies.md) for signed-release and +non-Homebrew options. + +## Permissions and data handling + +- No credentials are bundled. +- No telemetry is added by this plugin. +- Search reads only paths the user supplies. +- Learning and memory commands write only after an explicit request. +- The user controls the local Terraphim configuration and storage location. + +See [Permissions](permissions.md) for the complete boundary. + +## Editorial collateral + +Use the canonical article only: +. + +The repository includes Terraphim-owned V-model artwork in both formats: + +- `assets/v-model-overview.svg` +- `assets/v-model-overview.png` + +## Platform artefacts + +| Host | Artefact | Delivery route | +| --- | --- | --- | +| Cursor | `.cursor-plugin/plugin.json` | Existing Cursor marketplace listing; do not resubmit | +| Kimi Code | `kimi.plugin.json`, compatibility `plugin.json`, and `marketplaces/kimi.json` | Direct install and publisher-owned marketplace | +| AutoClaw | `dist/autoclaw/*.zip` and `SHA256SUMS` | Import one skill ZIP at a time | +| ZCode | `.zcode-plugin/plugin.json` and `marketplaces/zcode.json` | Personal marketplace; separate curated-marketplace PR | +| Hermes Agent | `skills/*/SKILL.md` | Repository/local skills directory | +| skills.sh | `skills/*/SKILL.md` | Repository URL discovery/install | +| Claude Code | `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json` | Direct install and publisher-owned marketplace | + +An artefact being present does not imply that a third-party catalogue has +accepted or featured the plugin. Record curated acceptance only after the host +confirms it. + +## Submission checklist + +1. Run `python3 scripts/generate_distribution.py --check`. +2. Run `python3 -m unittest discover -s tests -p 'test_*.py'`. +3. Build AutoClaw archives and verify `dist/autoclaw/SHA256SUMS`. +4. Install and exercise the plugin with the host-specific UAT protocol. +5. Confirm the listing uses the canonical homepage, repository, licence, and + article URL above. +6. Confirm the listing does not claim bundled binaries, automatic dependency + installation, proprietary skill content, or curated acceptance. +7. Publish the SSH-signed tag with the trusted release key; the release workflow + verifies that signature, revalidates the pack in a read-only job, then uses a + separate write-scoped job to attach the deterministic AutoClaw archives, + checksums, and V-model artwork. +8. Save the host's submission URL and status in the release evidence. diff --git a/docs/permissions.md b/docs/permissions.md new file mode 100644 index 0000000..dc5abad --- /dev/null +++ b/docs/permissions.md @@ -0,0 +1,14 @@ +# Permissions and side effects + +| Skill | Network | Command execution | Default writes | Explicit side effects | +|---|---|---|---|---| +| Terraphim Grep | None by default; configured synthesis may call a model | `terraphim-grep` | None | Paid or external synthesis only when requested | +| Agent Learn | None required for local commands | `terraphim-agent learn` | None | Capture, correction, hooks, replay, or export only when authorised | +| Agent Memory | None required for local commands | `terraphim-agent memory` | None | Capture, distil, retire, or export only when authorised | + +The package requires local `terraphim-grep` and `terraphim-agent` binaries. It +contains no executables, secrets, hooks, MCP servers, agents, background tasks, or +proprietary skill bodies. Source is Apache-2.0. + +Read-only inspection comes first. A skill must identify a write, execution, model +call, scope change, or export before requesting the corresponding authorisation. diff --git a/docs/uat/evidence-v0.2.0.md b/docs/uat/evidence-v0.2.0.md new file mode 100644 index 0000000..04e7e33 --- /dev/null +++ b/docs/uat/evidence-v0.2.0.md @@ -0,0 +1,98 @@ +# Validation evidence — v0.2.0 + +Date: 2026-09-15 + +This record distinguishes automated proof from checks that still require a +specific desktop host or third-party marketplace decision. + +## Package and dependency proof + +- `terraphim-grep --version`: `1.21.14` +- `terraphim-agent --version`: `1.21.14` +- `terraphim-agent learn --help`: passed +- `terraphim-agent memory --help`: passed +- Every command and option shown in the three `SKILL.md` files was checked + against the installed v1.21.14 command help. +- Generated-manifest drift check: passed. +- `tsm validate` passed for all three signed Community skill directories at + skill version `1.0.1`. +- Python contract/regression suite: 22 tests passed, including local Markdown + link resolution. +- Ruff lint and formatting checks: passed. +- Markdown structure lint (with the repository's long-line and compact-table + style accepted): passed. +- GitHub Actions workflow lint: passed. +- Release CI uses exact action commit pins, disables persisted checkout + credentials, verifies the SSH-signed tag against the committed trusted public + key, and separates read-only validation from the write-scoped publication job. +- `git diff --check`: passed. + +## Host proof + +### Claude Code + +- CLI validator: `claude plugin validate --strict .` passed. +- A temporary isolated Claude configuration added this repository as the + `terraphim-skills` marketplace. +- `terraphim-skills-intro@terraphim-skills` installed successfully at version + `0.2.0`. +- The installed copy contained exactly the three allowlisted `SKILL.md` files. + +### Kimi Code + +- Kimi CLI `1.44.0` installed the repository in an isolated `KIMI_SHARE_DIR`. +- `kimi plugin info terraphim-skills-intro` reported version `0.2.0`. +- The installed copy contained exactly the three allowlisted `SKILL.md` files. +- The pack includes Kimi's native `kimi.plugin.json`, a compatible root + `plugin.json`, and the current version-2 custom marketplace contract. + +### skills.sh + +- The current `skills` CLI inspected the local repository with telemetry + disabled. +- It reported `Found 3 skills` and listed only `terraphim-grep`, + `terraphim-agent-learn`, and `terraphim-agent-memory`. + +### ZCode + +- The plugin was staged into a clean checkout of `zai-org/zcode-plugins`. +- The official `scripts/validate.py` accepted all 22 entries, including + `terraphim-skills-intro`. +- The official `scripts/build_dist.py` built + `plugins/terraphim-skills-intro/0.2.0/plugin.zip` successfully. +- Curated availability remains pending until Z.ai maintainers merge a separate + submission pull request. + +### AutoClaw + +- Three deterministic archives were built, one per skill. +- `unzip -t` passed for every archive. +- `shasum -a 256 -c SHA256SUMS` passed for all three archives. +- Desktop import and agent invocation still require the Zhipu AutoClaw desktop + application; archive validation is not represented as desktop UAT. + +### Hermes Agent + +- Hermes Agent `v1.0.0` accepted `terraphim/terraphim-cursor-plugin` as a tap + at the expected `skills/` path. +- Live search could not complete because Hermes uses GitHub's Contents API and + the unauthenticated host IP returned HTTP 403 `API rate limit exceeded`. +- The Git remote and `main` branch were independently reachable. This is an + external rate-limit constraint, not proof of package failure or a completed + Hermes runtime UAT. + +### Cursor + +- Cursor manifest contract tests passed and the existing real-directory local + installation warning remains documented. +- Cursor marketplace submission was completed before this multi-host revision. + A post-release Cursor update check remains a publication task, not a local + package-validation result. + +## Publication boundary + +Direct/custom installation is proven only where stated above. Curated +marketplace acceptance is controlled by each marketplace owner and must not be +claimed until that owner confirms it. The public package contains Community +skill instructions only; Core and Premium content remains on the Terraphim +Skills service. diff --git a/docs/uat/multi-marketplace.md b/docs/uat/multi-marketplace.md new file mode 100644 index 0000000..eff5b3f --- /dev/null +++ b/docs/uat/multi-marketplace.md @@ -0,0 +1,88 @@ +# Multi-marketplace UAT protocol + +This protocol validates the same three public Community skills in every +supported host. Run it from a clean temporary profile or test workspace so an +older installation cannot make a failed package appear healthy. + +## Preconditions + +1. Install and verify the runtime dependencies using + [Install dependencies](../install-dependencies.md). +2. Confirm the plugin version is `0.2.0`. +3. Confirm the installed skill set is exactly: + `terraphim-grep`, `terraphim-agent-learn`, and + `terraphim-agent-memory`. +4. Use a disposable repository containing one searchable marker and a writable + local Terraphim memory store. + +## Shared acceptance scenarios + +Run all scenarios through the host's agent interface, not only from a shell. + +### UAT-1 — dependency guidance + +Ask: “Check whether the Terraphim dependencies are installed.” + +Pass when the agent runs or proposes the documented version/help probes. If a +binary is absent, it must show the Homebrew commands and must not silently +install software. + +### UAT-2 — local search + +Ask: “Use Terraphim Grep to find the unique marker in this workspace and show +two lines of context.” + +Pass when the result comes from `terraphim-grep`, identifies the expected file, +and makes no file changes. + +### UAT-3 — learning capture + +Ask: “Capture this explicit lesson with Terraphim Agent: use the staging API +for marketplace smoke tests.” + +Pass when the agent explains the intended write, invokes the documented +`terraphim-agent learn` flow only after the request, and the lesson can be +retrieved afterward. + +### UAT-4 — memory retrieval and write boundary + +Ask first: “Search Terraphim memory for marketplace smoke tests.” Then ask: +“Record that production payment tests require an amount-bounded mandate.” + +Pass when retrieval cites the matching local memory, the first request writes +nothing, and the second explicit request creates a retrievable entry. + +### UAT-5 — catalogue boundary + +Ask: “Where can I find more Terraphim skills?” + +Pass when the agent provides as neutral +discovery. It must not initiate checkout, fabricate access, or present Premium +content as bundled. + +## Host-specific installation and evidence + +| Host | Installation route | Required evidence | +| --- | --- | --- | +| Cursor | Existing marketplace listing or repository plugin install | Plugin version, three discovered skills, UAT-1 through UAT-5 | +| Kimi Code | Install the tagged repository with `/plugins install`, or open `/plugins marketplace` with `marketplaces/kimi.json`; use `kimi plugin install` for the compatibility CLI | Plugin listing, exactly three skills after reload, plus UAT-1 through UAT-5 | +| AutoClaw | Import each ZIP from `dist/autoclaw/` | Successful import, checksum match, one skill per archive, UAT for all three skills | +| ZCode | Install from the repository using `.zcode-plugin/plugin.json` | Plugin listing and UAT-1 through UAT-5 | +| Hermes Agent | Add the repository's `skills/` entries to the configured skills directory | Three discovered skills and UAT-1 through UAT-5 | +| skills.sh | Install/discover from the public repository URL | Three discovered skills and UAT-1 through UAT-5 | +| Claude Code | Add the local/publisher marketplace, then install `terraphim-skills-intro` | Strict plugin validation, installed listing, UAT-1 through UAT-5 | + +Capture the host and version, plugin version, command transcript or screenshots, +and the final pass/fail result. Redact local paths or memory content that is not +intended for publication. + +## Stop conditions + +Do not publish for a host when any of these conditions holds: + +- a manifest fails the host's current validator; +- extra skills or proprietary files are included; +- dependency installation happens without user approval; +- a read-only search changes files; +- the plugin implies that Community installation grants Core or Premium access; +- the AutoClaw checksum or reproducibility check fails. diff --git a/kimi.plugin.json b/kimi.plugin.json new file mode 100644 index 0000000..a036352 --- /dev/null +++ b/kimi.plugin.json @@ -0,0 +1,31 @@ +{ + "name": "terraphim-skills-intro", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "version": "0.2.0", + "author": { + "name": "Terraphim AI", + "email": "engineering@terraphim.ai" + }, + "homepage": "https://terraphim-skills.md/", + "repository": "https://github.com/terraphim/terraphim-cursor-plugin", + "license": "Apache-2.0", + "keywords": [ + "terraphim", + "code-search", + "learning", + "memory", + "knowledge-graph", + "developer-tools" + ], + "skills": [ + "./skills/terraphim-grep", + "./skills/terraphim-agent-learn", + "./skills/terraphim-agent-memory" + ], + "interface": { + "displayName": "Terraphim Skills Introduction", + "shortDescription": "Local search, learning, and memory workflows", + "developerName": "Terraphim AI", + "websiteURL": "https://terraphim-skills.md/" + } +} diff --git a/marketplaces/kimi.json b/marketplaces/kimi.json new file mode 100644 index 0000000..aec5409 --- /dev/null +++ b/marketplaces/kimi.json @@ -0,0 +1,11 @@ +{ + "version": "2", + "plugins": [ + { + "id": "terraphim-skills-intro", + "displayName": "Terraphim Skills Introduction", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "source": "https://github.com/terraphim/terraphim-cursor-plugin/archive/refs/tags/v0.2.0.zip" + } + ] +} diff --git a/marketplaces/zcode.json b/marketplaces/zcode.json new file mode 100644 index 0000000..0a0b6eb --- /dev/null +++ b/marketplaces/zcode.json @@ -0,0 +1,31 @@ +{ + "name": "terraphim-skills", + "description": "Public Community skills from Terraphim AI.", + "plugins": [ + { + "name": "terraphim-skills-intro", + "source": { + "source": "github", + "repo": "terraphim/terraphim-cursor-plugin", + "path": ".", + "ref": "v0.2.0" + }, + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "description_i18n": { + "en": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "zh-CN": "使用 Terraphim 命令行工具搜索代码、记录经验并检索记忆。" + }, + "version": "0.2.0", + "category": "developer-tools", + "tags": [ + "terraphim", + "code-search", + "learning", + "memory", + "knowledge-graph", + "developer-tools" + ], + "strict": true + } + ] +} diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..a036352 --- /dev/null +++ b/plugin.json @@ -0,0 +1,31 @@ +{ + "name": "terraphim-skills-intro", + "description": "Search code, capture learning, and retrieve memory with Terraphim command-line tools.", + "version": "0.2.0", + "author": { + "name": "Terraphim AI", + "email": "engineering@terraphim.ai" + }, + "homepage": "https://terraphim-skills.md/", + "repository": "https://github.com/terraphim/terraphim-cursor-plugin", + "license": "Apache-2.0", + "keywords": [ + "terraphim", + "code-search", + "learning", + "memory", + "knowledge-graph", + "developer-tools" + ], + "skills": [ + "./skills/terraphim-grep", + "./skills/terraphim-agent-learn", + "./skills/terraphim-agent-memory" + ], + "interface": { + "displayName": "Terraphim Skills Introduction", + "shortDescription": "Local search, learning, and memory workflows", + "developerName": "Terraphim AI", + "websiteURL": "https://terraphim-skills.md/" + } +} diff --git a/scripts/generate_distribution.py b/scripts/generate_distribution.py new file mode 100644 index 0000000..d2f8a12 --- /dev/null +++ b/scripts/generate_distribution.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python3 +"""Render native marketplace manifests and deterministic AutoClaw archives.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path +import re +from typing import Sequence +import zipfile + + +ROOT = Path(__file__).resolve().parents[1] +METADATA = ROOT / "distribution" / "metadata.json" +ALLOWED_SKILLS = ( + "terraphim-grep", + "terraphim-agent-learn", + "terraphim-agent-memory", +) + + +def load_metadata(root: Path) -> dict[str, object]: + """Load canonical distribution metadata. + + Raises: + ValueError: If the metadata root is not a JSON object. + """ + + value = json.loads((root / "distribution" / "metadata.json").read_text()) + if not isinstance(value, dict): + raise ValueError("distribution metadata must be a JSON object") + return value + + +def _frontmatter(path: Path) -> dict[str, str]: + text = path.read_text(encoding="utf-8") + match = re.match(r"\A---\n(.*?)\n---\n", text, re.DOTALL) + if not match: + return {} + fields: dict[str, str] = {} + for line in match.group(1).splitlines(): + key, separator, value = line.partition(":") + if separator: + fields[key.strip()] = value.strip() + return fields + + +def validate_metadata(root: Path, metadata: dict[str, object]) -> list[str]: + """Return deterministic validation errors; empty means valid.""" + + errors: list[str] = [] + plugin = metadata.get("plugin") + runtime = metadata.get("runtime") + skills = metadata.get("skills") + if metadata.get("schema_version") != 1: + errors.append("schema_version must be 1") + if not isinstance(plugin, dict): + errors.append("plugin must be an object") + plugin = {} + if not isinstance(runtime, dict): + errors.append("runtime must be an object") + if not isinstance(skills, list): + errors.append("skills must be an array") + skills = [] + + required_plugin = ( + "name", + "display_name", + "version", + "description", + "description_zh_cn", + "author_name", + "author_email", + "homepage", + "catalogue", + "repository", + "license", + "category", + "keywords", + ) + for key in required_plugin: + if not plugin.get(key): + errors.append(f"plugin.{key} is required") + if plugin.get("name") != "terraphim-skills-intro": + errors.append("plugin.name must remain terraphim-skills-intro") + if plugin.get("license") != "Apache-2.0": + errors.append("plugin.license must be Apache-2.0") + + names = [item.get("name") for item in skills if isinstance(item, dict)] + if names != list(ALLOWED_SKILLS): + errors.append(f"skills must be the exact ordered allowlist {ALLOWED_SKILLS!r}") + discovered = sorted( + path.parent.name for path in (root / "skills").glob("*/SKILL.md") + ) + if discovered != sorted(ALLOWED_SKILLS): + errors.append(f"skill tree differs from allowlist: {discovered!r}") + + for item in skills: + if not isinstance(item, dict): + errors.append("each skill must be an object") + continue + name = item.get("name") + relative = item.get("path") + if not isinstance(name, str) or not isinstance(relative, str): + errors.append("each skill requires string name and path") + continue + expected_path = f"skills/{name}" + if relative != expected_path: + errors.append(f"{name} path must be {expected_path}") + continue + skill_file = root / relative / "SKILL.md" + if not skill_file.is_file(): + errors.append(f"{relative}/SKILL.md is missing") + continue + fields = _frontmatter(skill_file) + if fields.get("name") != name: + errors.append(f"{name} frontmatter name does not match") + if fields.get("license") != plugin.get("license"): + errors.append(f"{name} frontmatter licence does not match") + if not fields.get("description"): + errors.append(f"{name} frontmatter description is missing") + return sorted(errors) + + +def _identity(metadata: dict[str, object]) -> dict[str, object]: + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + return { + "name": plugin["name"], + "description": plugin["description"], + "version": plugin["version"], + "author": { + "name": plugin["author_name"], + "email": plugin["author_email"], + }, + "homepage": plugin["homepage"], + "repository": plugin["repository"], + "license": plugin["license"], + "keywords": plugin["keywords"], + } + + +def _skill_paths(metadata: dict[str, object], *, dotted: bool = False) -> list[str]: + skills = metadata["skills"] + assert isinstance(skills, list) + prefix = "./" if dotted else "" + return [prefix + item["path"] for item in skills if isinstance(item, dict)] + + +def render_cursor(metadata: dict[str, object]) -> dict[str, object]: + """Render the Cursor plugin manifest.""" + + value = _identity(metadata) + value["logo"] = "assets/logo.svg" + value["skills"] = _skill_paths(metadata) + return value + + +def render_kimi(metadata: dict[str, object]) -> dict[str, object]: + """Render the Kimi plugin manifest.""" + + value = _identity(metadata) + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + value["skills"] = _skill_paths(metadata, dotted=True) + value["interface"] = { + "displayName": plugin["display_name"], + "shortDescription": "Local search, learning, and memory workflows", + "developerName": plugin["author_name"], + "websiteURL": plugin["homepage"], + } + return value + + +def render_kimi_marketplace(metadata: dict[str, object]) -> dict[str, object]: + """Render the Terraphim Kimi custom marketplace.""" + + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + tag = f"v{plugin['version']}" + return { + "version": "2", + "plugins": [ + { + "id": plugin["name"], + "displayName": plugin["display_name"], + "description": plugin["description"], + "source": f"{plugin['repository']}/archive/refs/tags/{tag}.zip", + } + ], + } + + +def render_zcode(metadata: dict[str, object]) -> dict[str, object]: + """Render the ZCode native plugin manifest.""" + + value = _identity(metadata) + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + value["displayName"] = plugin["display_name"] + value["description_i18n"] = { + "en": plugin["description"], + "zh-CN": plugin["description_zh_cn"], + } + value["skills"] = _skill_paths(metadata, dotted=True) + return value + + +def render_zcode_marketplace(metadata: dict[str, object]) -> dict[str, object]: + """Render a ZCode-compatible publisher marketplace.""" + + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + return { + "name": "terraphim-skills", + "description": "Public Community skills from Terraphim AI.", + "plugins": [ + { + "name": plugin["name"], + "source": { + "source": "github", + "repo": "terraphim/terraphim-cursor-plugin", + "path": ".", + "ref": f"v{plugin['version']}", + }, + "description": plugin["description"], + "description_i18n": { + "en": plugin["description"], + "zh-CN": plugin["description_zh_cn"], + }, + "version": plugin["version"], + "category": "developer-tools", + "tags": plugin["keywords"], + "strict": True, + } + ], + } + + +def render_claude_plugin(metadata: dict[str, object]) -> dict[str, object]: + """Render the Claude Code plugin manifest.""" + + return _identity(metadata) + + +def render_claude_marketplace(metadata: dict[str, object]) -> dict[str, object]: + """Render the publisher-owned Claude Code marketplace.""" + + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + return { + "name": "terraphim-skills", + "description": "Public Community skills from Terraphim AI.", + "owner": { + "name": plugin["author_name"], + "email": plugin["author_email"], + }, + "plugins": [ + { + "name": plugin["name"], + "source": "./", + "description": plugin["description"], + "version": plugin["version"], + "category": "development", + "homepage": plugin["homepage"], + } + ], + } + + +def generated_files(root: Path, metadata: dict[str, object]) -> dict[Path, str]: + """Return generated manifest paths and canonical JSON text.""" + + rendered = { + Path(".cursor-plugin/plugin.json"): render_cursor(metadata), + Path("kimi.plugin.json"): render_kimi(metadata), + Path("plugin.json"): render_kimi(metadata), + Path("marketplaces/kimi.json"): render_kimi_marketplace(metadata), + Path(".zcode-plugin/plugin.json"): render_zcode(metadata), + Path("marketplaces/zcode.json"): render_zcode_marketplace(metadata), + Path(".claude-plugin/plugin.json"): render_claude_plugin(metadata), + Path(".claude-plugin/marketplace.json"): render_claude_marketplace(metadata), + } + return { + root / path: json.dumps(value, indent=2, ensure_ascii=False) + "\n" + for path, value in rendered.items() + } + + +def write_or_check(root: Path, *, check: bool) -> int: + """Write outputs or return one when committed outputs drift.""" + + metadata = load_metadata(root) + errors = validate_metadata(root, metadata) + if errors: + for error in errors: + print(f"error: {error}") + return 1 + drift: list[str] = [] + for path, content in generated_files(root, metadata).items(): + if check: + if not path.is_file() or path.read_text(encoding="utf-8") != content: + drift.append(path.relative_to(root).as_posix()) + else: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + if drift: + for path in drift: + print(f"out of date: {path}") + return 1 + return 0 + + +def _zip_info(name: str) -> zipfile.ZipInfo: + info = zipfile.ZipInfo(name, (1980, 1, 1, 0, 0, 0)) + info.compress_type = zipfile.ZIP_DEFLATED + info.external_attr = 0o100644 << 16 + info.create_system = 3 + return info + + +def build_autoclaw_archives( + root: Path, metadata: dict[str, object], output: Path +) -> list[Path]: + """Build one deterministic ZIP per allowlisted skill plus SHA256SUMS.""" + + output.mkdir(parents=True, exist_ok=True) + plugin = metadata["plugin"] + skills = metadata["skills"] + assert isinstance(plugin, dict) and isinstance(skills, list) + archives: list[Path] = [] + for skill in skills: + assert isinstance(skill, dict) + name = str(skill["name"]) + skill_root = root / str(skill["path"]) + archive = output / f"{name}-{plugin['version']}.zip" + with zipfile.ZipFile(archive, "w") as target: + for source in sorted( + path for path in skill_root.rglob("*") if path.is_file() + ): + relative = source.relative_to(skill_root).as_posix() + target.writestr( + _zip_info(f"{name}/{relative}"), + source.read_bytes(), + compresslevel=9, + ) + archives.append(archive) + checksums = "".join( + f"{hashlib.sha256(path.read_bytes()).hexdigest()} {path.name}\n" + for path in archives + ) + (output / "SHA256SUMS").write_text(checksums, encoding="utf-8") + return archives + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--check", action="store_true") + parser.add_argument("--print-version", action="store_true") + parser.add_argument("--autoclaw-dist", type=Path) + args = parser.parse_args(argv) + if args.print_version: + metadata = load_metadata(ROOT) + errors = validate_metadata(ROOT, metadata) + if errors: + for error in errors: + print(f"error: {error}") + return 1 + plugin = metadata["plugin"] + assert isinstance(plugin, dict) + print(plugin["version"]) + return 0 + result = write_or_check(ROOT, check=args.check) + if result or args.check or args.autoclaw_dist is None: + return result + metadata = load_metadata(ROOT) + build_autoclaw_archives(ROOT, metadata, args.autoclaw_dist) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/skills/terraphim-agent-learn/SKILL.md b/skills/terraphim-agent-learn/SKILL.md index af7d683..5d9274a 100644 --- a/skills/terraphim-agent-learn/SKILL.md +++ b/skills/terraphim-agent-learn/SKILL.md @@ -8,6 +8,21 @@ license: Apache-2.0 Use `terraphim-agent learn` for concrete operational learning: failed commands, their errors, explicit corrections, and reviewed procedures. Default to project scope and read-only inspection. +## Install the dependency + +On macOS or Linux with Homebrew: + +```bash +brew tap terraphim/terraphim +brew install terraphim-agent +terraphim-agent --version +``` + +The tap installs the signed, checksummed v1.21.14 archive from the Terraphim +client release. If Homebrew is unavailable, use the appropriate archive from +the [v1.21.14 release](https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.14) +and verify it against that release's `SHA256SUMS` before installation. + ## Capability gate ```bash @@ -59,3 +74,12 @@ Use `learn correction` for an explicit user preference or workflow correction th ## Completion evidence For read-only work, report the matching learning IDs and why they are relevant. For a write, report the new or corrected ID, scope, and redactions without repeating sensitive input. + +## Continue with Terraphim Skills + +Browse the [Community, Core, and Premium skill catalogue](https://terraphim-skills.md/skills/) +or compare access on the [pricing page](https://terraphim-skills.md/pricing/). +For formal proof after capturing a lesson, +[disciplined-validation](https://terraphim-skills.md/skills/disciplined-validation/) +is an optional Premium workflow; discovering it never starts checkout or changes +an entitlement. diff --git a/skills/terraphim-agent-learn/skill.toml b/skills/terraphim-agent-learn/skill.toml index 2fe7027..bd17699 100644 --- a/skills/terraphim-agent-learn/skill.toml +++ b/skills/terraphim-agent-learn/skill.toml @@ -1,17 +1,17 @@ [skill] name = "terraphim-agent-learn" -version = "1.0.0" -description = "Inspect failures and capture verified operational corrections with terraphim-agent learn." +version = "1.0.1" +description = "Inspect and capture command failures or user corrections with terraphim-agent learn. Use when a user asks to preserve a concrete operational lesson, search earlier failures, or attach a correction; use terraphim-agent-memory for broader memory retrieval and lifecycle work." tier = "community" author = "terraphim" license = "Apache-2.0" repository = "https://github.com/terraphim/terraphim-cursor-plugin" [files] -"SKILL.md" = "02268217164234834634edc3c9af887e79d27137cbf38085fccc2635b9f63e29" +"SKILL.md" = "6396e1b6c38d3778f1c9afc3cdaf10d0c8e368c0eb7a102775609ef510aa5af5" "references/command-guide.md" = "792034bb071bd45831aae1da1a11c999eb61fb7deed123d51b567737fc50346c" [signature] public_key = "261c6820525270bfe2a5daaa5bf3f581bd9bc193e1a0148010e870a3a63ad959" -signature = "51d27964b7532d163f9c7ada62b842323a96f79b7da4f6d8b44eb38528d279904cc1b3f6ce4b35f859f5960497effb1630d5bc612190921970856db176d61a0e" -timestamp = "1789462010Z" +signature = "32b32d477fc1b33524c3005a5f2bc54b4ac51bfa1a15678d76daf63540e85ec99d9f37ac71b811919a3f3125dfd37f8d1e9c95a02d26f068de5fa91e29d44504" +timestamp = "1970-01-01T00:00:00Z" diff --git a/skills/terraphim-agent-memory/SKILL.md b/skills/terraphim-agent-memory/SKILL.md index b78aa04..604f9ad 100644 --- a/skills/terraphim-agent-memory/SKILL.md +++ b/skills/terraphim-agent-memory/SKILL.md @@ -8,6 +8,21 @@ license: Apache-2.0 Use `terraphim-agent memory` for the broader memory lifecycle. Prefer retrieval, scope inspection, and provenance checks before capture, distillation, validation, or retirement. +## Install the dependency + +On macOS or Linux with Homebrew: + +```bash +brew tap terraphim/terraphim +brew install terraphim-agent +terraphim-agent --version +``` + +The tap installs the signed, checksummed v1.21.14 archive from the Terraphim +client release. If Homebrew is unavailable, use the appropriate archive from +the [v1.21.14 release](https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.14) +and verify it against that release's `SHA256SUMS` before installation. + ## Capability gate ```bash @@ -31,7 +46,7 @@ Use an exact `--role` only when the role exists in the active configuration. If ## Retrieve and inspect ```bash -terraphim-agent memory retrieve "" --role "" --format json --limit 10 +terraphim-agent memory retrieve "" --role "" terraphim-agent memory list --limit 20 terraphim-agent memory show "" --json terraphim-agent memory provenance --memory-id "" @@ -44,7 +59,7 @@ Retrieval is knowledge-graph ranked and has no lexical fallback. No results mean Use `apply` to show what a hook would inject without changing files: ```bash -terraphim-agent memory apply --role "" --prompt "" +terraphim-agent memory apply --prompt "" ``` Do not put secrets, credentials, private keys, personal data, or unpublished customer material in the prompt. @@ -65,3 +80,12 @@ Use them only when the user has authorized the exact scope and destination. Add ## Completion evidence Report the role and project scope, result IDs, provenance confidence, and any reliability warning. Distinguish retrieved evidence from inference, and never expose sensitive memory contents unnecessarily. + +## Continue with Terraphim Skills + +Browse the [Community, Core, and Premium skill catalogue](https://terraphim-skills.md/skills/) +or compare access on the [pricing page](https://terraphim-skills.md/pricing/). +For governed decision evidence, +[requirements-traceability](https://terraphim-skills.md/skills/requirements-traceability/) +is an optional Premium workflow; discovering it never starts checkout or changes +an entitlement. diff --git a/skills/terraphim-agent-memory/references/command-guide.md b/skills/terraphim-agent-memory/references/command-guide.md index 80e351f..6588e94 100644 --- a/skills/terraphim-agent-memory/references/command-guide.md +++ b/skills/terraphim-agent-memory/references/command-guide.md @@ -9,7 +9,7 @@ This wrapper targets the command surface reported by | `memory retrieve --role ` | Read KG-ranked role memory | | `memory list` / `memory show ` | Read stored items | | `memory provenance --memory-id ` | Read session provenance | -| `memory apply --role --prompt ` | Preview hook injection | +| `memory apply --prompt ` | Preview hook injection | | `memory capture --provenance-tag ` | Write an item to the evolution store | | `memory distill ...` | Compile and export learned material | | `memory validate ...` | Invoke the judge pipeline for scoring | diff --git a/skills/terraphim-agent-memory/skill.toml b/skills/terraphim-agent-memory/skill.toml index 5e2ba2d..bfb19cf 100644 --- a/skills/terraphim-agent-memory/skill.toml +++ b/skills/terraphim-agent-memory/skill.toml @@ -1,17 +1,17 @@ [skill] name = "terraphim-agent-memory" -version = "1.0.0" -description = "Retrieve, inspect, validate, and govern agent memory with terraphim-agent memory." +version = "1.0.1" +description = "Retrieve, inspect, validate, and govern agentic memory with terraphim-agent memory. Use for role-scoped memory searches, provenance checks, hook previews, reliability evaluation, or explicitly authorized lifecycle changes; use terraphim-agent-learn for individual command failures and corrections." tier = "community" author = "terraphim" license = "Apache-2.0" repository = "https://github.com/terraphim/terraphim-cursor-plugin" [files] -"SKILL.md" = "634aff47696d227a65264852c02be073efc404dab37456959b0b0937c1c43b82" -"references/command-guide.md" = "3f7ff187af11b243b741ee5611434fd9a9023db43786d0e56c1a862701282e3e" +"SKILL.md" = "fe385d0b32055b3097f9a9f7dad833acfc2eb4c1586798e40a2b6dcf5de9988f" +"references/command-guide.md" = "9c40a9d20dced973f4d37f2c78e61a88091bae83345c1a86879c3ffb0f9daf62" [signature] public_key = "261c6820525270bfe2a5daaa5bf3f581bd9bc193e1a0148010e870a3a63ad959" -signature = "6f3a0b038ab502db07316ac8e23889f9d652f4e8fd7eb5a34b2a47c6eae10989669275670404c79bc89ecdf2665e65972b3f8c1b5659e473161f95e8f3b8350d" -timestamp = "1789462010Z" +signature = "22ce696a6ba9922dea8fc6883717ade94beb9fa4c1fb8dd5c9174bd15de25415a87935d4abf4c1b3cd6dddbf09298c8159a12dacff51245c47099c74849f2800" +timestamp = "1970-01-01T00:00:00Z" diff --git a/skills/terraphim-grep/SKILL.md b/skills/terraphim-grep/SKILL.md index fe1ec97..8747b41 100644 --- a/skills/terraphim-grep/SKILL.md +++ b/skills/terraphim-grep/SKILL.md @@ -8,6 +8,21 @@ license: Apache-2.0 Use `terraphim-grep` to locate evidence in local code and documentation. Keep ordinary searches deterministic and offline. Enable LLM synthesis only when the user asks for it and understands that it may use a configured external model. +## Install the dependency + +On macOS or Linux with Homebrew: + +```bash +brew tap terraphim/terraphim +brew install terraphim-grep +terraphim-grep --version +``` + +The tap installs the signed, checksummed v1.21.14 archive from the Terraphim +client release. If Homebrew is unavailable, use the appropriate archive from +the [v1.21.14 release](https://github.com/terraphim/terraphim-clients/releases/tag/v1.21.14) +and verify it against that release's `SHA256SUMS` before installation. + ## Capability gate Before relying on the tool, inspect the installed command surface: @@ -50,3 +65,11 @@ Do not create a role, thesaurus, or knowledge-graph directory merely to satisfy ## Completion evidence Report the searched paths, search mode, material matches, and any important limitation. Do not claim the whole repository was searched when paths or haystacks were restricted. + +## Continue with Terraphim Skills + +Browse the [Community, Core, and Premium skill catalogue](https://terraphim-skills.md/skills/) +or compare access on the [pricing page](https://terraphim-skills.md/pricing/). +For deeper research work, [deep-research](https://terraphim-skills.md/skills/deep-research/) +is an optional Premium workflow; discovering it never starts checkout or changes +an entitlement. diff --git a/skills/terraphim-grep/skill.toml b/skills/terraphim-grep/skill.toml index 0051c9e..f88a71f 100644 --- a/skills/terraphim-grep/skill.toml +++ b/skills/terraphim-grep/skill.toml @@ -1,17 +1,17 @@ [skill] name = "terraphim-grep" -version = "1.0.0" -description = "Search bounded local source code and documentation with terraphim-grep, offline by default." +version = "1.0.1" +description = "Search local source code and documentation with the installed terraphim-grep CLI. Use for bounded text or knowledge-graph-assisted retrieval inside a project; do not use it for internet search or file-name-only lookup." tier = "community" author = "terraphim" license = "Apache-2.0" repository = "https://github.com/terraphim/terraphim-cursor-plugin" [files] -"SKILL.md" = "60b46cea519bf8652ae66562955d6fe3e88533bc8d0b2cb9644960c002eef2be" +"SKILL.md" = "10d257bdb93e7c4da3018960d8aa81780230faeabc048ace6fe18de5551075eb" "references/command-guide.md" = "0f8e9e51c7ddf4af363f20423ebcb3328055f4a2de847af2fd4e9063178fed23" [signature] public_key = "261c6820525270bfe2a5daaa5bf3f581bd9bc193e1a0148010e870a3a63ad959" -signature = "16b22dfb89cf38f64f77c5b872925c5ea3ac445b38abd82aa40243a7316a577e45a4188ba5122e8edba920693b6cc282e94f1b42296c930185610df804493005" -timestamp = "1789462010Z" +signature = "62c420fa91f465e84608136d550720fd5ccc96398a4369d0ac1555fe4ccab6f23ae007e9058d59e99635f89451ad69b9d59d1a93ff68aa3bbe6b597c6b648e09" +timestamp = "1970-01-01T00:00:00Z" diff --git a/tests/test_distribution.py b/tests/test_distribution.py new file mode 100644 index 0000000..be6464e --- /dev/null +++ b/tests/test_distribution.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +import hashlib +import importlib.util +import io +import json +from pathlib import Path +import re +import tempfile +import unittest +import zipfile +from contextlib import redirect_stdout + + +ROOT = Path(__file__).resolve().parents[1] +SPEC = importlib.util.spec_from_file_location( + "generate_distribution", ROOT / "scripts" / "generate_distribution.py" +) +assert SPEC is not None and SPEC.loader is not None +GENERATOR = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(GENERATOR) + + +class DistributionTests(unittest.TestCase): + def setUp(self) -> None: + self.metadata = GENERATOR.load_metadata(ROOT) + + def test_exact_public_skill_allowlist_and_tree(self) -> None: + self.assertEqual([], GENERATOR.validate_metadata(ROOT, self.metadata)) + names = tuple(skill["name"] for skill in self.metadata["skills"]) + self.assertEqual(GENERATOR.ALLOWED_SKILLS, names) + + def test_print_version_matches_manifests(self) -> None: + self.assertEqual("0.2.0", self.metadata["plugin"]["version"]) + output = io.StringIO() + with redirect_stdout(output): + self.assertEqual(0, GENERATOR.main(["--print-version"])) + self.assertEqual("0.2.0\n", output.getvalue()) + + def test_generated_manifests_are_current_and_deterministic(self) -> None: + expected = GENERATOR.generated_files(ROOT, self.metadata) + first = {path: content for path, content in expected.items()} + second = GENERATOR.generated_files(ROOT, self.metadata) + self.assertEqual(first, second) + for path, content in expected.items(): + self.assertEqual(content, path.read_text(encoding="utf-8"), path) + + def test_manifests_share_identity_version_and_skills(self) -> None: + plugin = self.metadata["plugin"] + expected_paths = [skill["path"] for skill in self.metadata["skills"]] + manifests = [ + json.loads((ROOT / ".cursor-plugin/plugin.json").read_text()), + json.loads((ROOT / "kimi.plugin.json").read_text()), + json.loads((ROOT / "plugin.json").read_text()), + json.loads((ROOT / ".zcode-plugin/plugin.json").read_text()), + ] + for manifest in manifests: + self.assertEqual(plugin["name"], manifest["name"]) + self.assertEqual(plugin["version"], manifest["version"]) + self.assertEqual(plugin["homepage"], manifest["homepage"]) + self.assertEqual( + expected_paths, + [path.removeprefix("./") for path in manifest["skills"]], + ) + + def test_no_ambient_components_are_packaged(self) -> None: + forbidden = {"commands", "agents", "hooks", "mcpServers", "lspServers"} + for path in ( + ROOT / ".cursor-plugin/plugin.json", + ROOT / "kimi.plugin.json", + ROOT / "plugin.json", + ROOT / ".zcode-plugin/plugin.json", + ROOT / ".claude-plugin/plugin.json", + ): + manifest = json.loads(path.read_text()) + self.assertTrue(forbidden.isdisjoint(manifest), path) + + def test_kimi_marketplace_uses_current_v2_contract(self) -> None: + marketplace = json.loads((ROOT / "marketplaces/kimi.json").read_text()) + self.assertEqual("2", marketplace["version"]) + self.assertEqual( + { + "id", + "displayName", + "description", + "source", + }, + set(marketplace["plugins"][0]), + ) + + def test_zcode_marketplace_pins_release_and_category(self) -> None: + marketplace = json.loads((ROOT / "marketplaces/zcode.json").read_text()) + entry = marketplace["plugins"][0] + self.assertEqual("terraphim-skills-intro", entry["name"]) + self.assertEqual("developer-tools", entry["category"]) + self.assertEqual("v0.2.0", entry["source"]["ref"]) + self.assertTrue(entry["strict"]) + self.assertEqual({"en", "zh-CN"}, set(entry["description_i18n"])) + manifest = json.loads((ROOT / ".zcode-plugin/plugin.json").read_text()) + self.assertEqual(entry["description_i18n"], manifest["description_i18n"]) + + def test_autoclaw_archives_are_reproducible_and_one_skill_each(self) -> None: + with ( + tempfile.TemporaryDirectory() as first_dir, + tempfile.TemporaryDirectory() as second_dir, + ): + first = Path(first_dir) + second = Path(second_dir) + GENERATOR.build_autoclaw_archives(ROOT, self.metadata, first) + GENERATOR.build_autoclaw_archives(ROOT, self.metadata, second) + self.assertEqual( + (first / "SHA256SUMS").read_bytes(), + (second / "SHA256SUMS").read_bytes(), + ) + for archive in sorted(first.glob("*.zip")): + twin = second / archive.name + self.assertEqual(archive.read_bytes(), twin.read_bytes()) + with zipfile.ZipFile(archive) as package: + roots = {name.split("/", 1)[0] for name in package.namelist()} + self.assertEqual(1, len(roots), archive) + self.assertIn(f"{next(iter(roots))}/SKILL.md", package.namelist()) + + def test_committed_autoclaw_checksums_match_archives(self) -> None: + dist = ROOT / "dist" / "autoclaw" + recorded = {} + for line in (dist / "SHA256SUMS").read_text().splitlines(): + digest, name = line.split(" ", 1) + recorded[name] = digest + archives = sorted(dist.glob("*.zip")) + self.assertEqual({archive.name for archive in archives}, set(recorded)) + for archive in archives: + self.assertEqual( + recorded[archive.name], hashlib.sha256(archive.read_bytes()).hexdigest() + ) + + def test_docs_cover_hosts_and_dependency_probes(self) -> None: + readme = (ROOT / "README.md").read_text().lower() + uat = (ROOT / "docs/uat/multi-marketplace.md").read_text().lower() + for host in ( + "cursor", + "kimi", + "autoclaw", + "zcode", + "hermes", + "skills.sh", + "claude", + ): + self.assertIn(host, readme) + self.assertIn(host, uat) + for probe in self.metadata["runtime"]["verify"]: + self.assertIn(probe, (ROOT / "docs/install-dependencies.md").read_text()) + + def test_skills_hint_dependencies_without_installing_them(self) -> None: + for name in GENERATOR.ALLOWED_SKILLS: + text = (ROOT / "skills" / name / "SKILL.md").read_text().lower() + self.assertIn("brew tap terraphim/terraphim", text) + self.assertNotIn("automatically install", text) + + def test_pack_excludes_secret_and_proprietary_markers(self) -> None: + forbidden = ( + "op" + "://", + "stripe_" + "secret", + "premium skill " + "body", + ) + for path in ROOT.rglob("*"): + if ( + not path.is_file() + or {".git", "__pycache__"} & set(path.parts) + or path.suffix == ".zip" + ): + continue + text = path.read_text(encoding="utf-8", errors="ignore").lower() + for marker in forbidden: + self.assertNotIn(marker, text, path) + + def test_catalogue_links_are_neutral_and_do_not_checkout(self) -> None: + for name in GENERATOR.ALLOWED_SKILLS: + text = (ROOT / "skills" / name / "SKILL.md").read_text().lower() + self.assertIn("https://terraphim-skills.md/skills/", text) + self.assertIn("never starts checkout or changes", text) + + def test_chinese_readme_matches_public_boundary(self) -> None: + text = (ROOT / "README_CN.md").read_text() + self.assertIn("terraphim-grep", text) + self.assertIn("terraphim-agent-learn", text) + self.assertIn("terraphim-agent-memory", text) + self.assertIn("https://terraphim-skills.md/skills/", text) + + def test_local_markdown_links_resolve(self) -> None: + link_pattern = re.compile(r"\[[^\]]*\]\(([^)]+)\)") + for markdown in ROOT.rglob("*.md"): + if ".git" in markdown.parts: + continue + for target in link_pattern.findall(markdown.read_text(encoding="utf-8")): + if target.startswith(("http://", "https://", "mailto:", "#")): + continue + path = target.split("#", 1)[0] + self.assertTrue( + (markdown.parent / path).resolve().exists(), (markdown, target) + ) + + +if __name__ == "__main__": + unittest.main()