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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
28 changes: 23 additions & 5 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
{
"name": "cavi-ai",
"owner": { "name": "Cavi AI", "url": "https://github.com/cavi-ai" },
"metadata": { "description": "Cavi AI plugins for agent hosts." },
"owner": {
"name": "Cavi AI",
"url": "https://github.com/cavi-ai"
},
"metadata": {
"description": "Cavi AI plugins for agent hosts."
},
"plugins": [
{
"name": "mlx-agent",
"source": { "source": "github", "repo": "cavi-ai/mlx-agent" },
"source": {
"source": "github",
"repo": "cavi-ai/mlx-agent",
"ref": "v0.10.0",
"sha": "6e6effd57bc4fce90760d938a939aef1f18e1f49"
},
"description": "Discover, verify, and wire local MLX-optimized models on Apple Silicon."
},
{
"name": "obsidian-agent",
"source": { "source": "github", "repo": "cavi-ai/obsidian-agent" },
"source": {
"source": "github",
"repo": "cavi-ai/obsidian-agent",
"ref": "v0.1.0",
"sha": "b0b0cf03658b4f74c632db54834cb9add337c40a"
},
"description": "Portable Obsidian vault workflows powered by the official Obsidian CLI."
},
{
"name": "loop-killer",
"source": { "source": "github", "repo": "cavi-ai/loop-killer" },
"source": {
"source": "github",
"repo": "cavi-ai/loop-killer"
},
"description": "Ends a stop-hook re-prompt loop: after repeated re-prompt turns with no tool work, it clears the active goal and says so."
}
]
Expand Down
94 changes: 94 additions & 0 deletions .github/workflows/sync-plugin-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Sync plugin release

on:
repository_dispatch:
types: [cavi-oss-release]
workflow_dispatch:
inputs:
name:
description: Catalog plugin that released
required: true
type: choice
options: [mlx-agent, obsidian-agent, loop-killer]
tag:
description: Release tag, for example v0.10.0
required: true

permissions:
contents: read

concurrency:
group: sync-plugin-release-${{ github.event.client_payload.slug || inputs.name }}
cancel-in-progress: false

jobs:
sync:
if: github.event_name == 'workflow_dispatch' || contains(fromJSON('["mlx-agent","obsidian-agent","loop-killer"]'), github.event.client_payload.slug)
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
NAME: ${{ github.event.client_payload.slug || inputs.name }}
TAG: ${{ github.event.client_payload.tag || inputs.tag }}
COMMIT: ${{ github.event.client_payload.commit || '' }}
REPOSITORY: ${{ github.event.client_payload.repository || '' }}
steps:
- name: Check the release identity
run: |
set -euo pipefail
[[ "$TAG" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] || { echo "Tag must be vX.Y.Z: $TAG"; exit 1; }
if [ -n "$REPOSITORY" ] && [ "$REPOSITORY" != "cavi-ai/$NAME" ]; then echo "Repository $REPOSITORY does not match $NAME"; exit 1; fi
if [ -n "$COMMIT" ] && ! [[ "$COMMIT" =~ ^[0-9a-f]{40}$ ]]; then echo "Commit must be a full lowercase SHA: $COMMIT"; exit 1; fi

- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
repository: cavi-ai/${{ env.NAME }}
ref: refs/tags/${{ env.TAG }}
path: .upstream
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22

- name: Point every host at the release
run: |
set -euo pipefail
resolved="$(git -C .upstream rev-parse HEAD)"
if [ -n "$COMMIT" ] && [ "$resolved" != "$COMMIT" ]; then echo "$TAG resolves to $resolved, not $COMMIT"; exit 1; fi
node scripts/sync-release.mjs --name "$NAME" --source .upstream --tag "$TAG" --commit "$resolved"
rm -rf .upstream
node --test
node scripts/validate-catalog.mjs
echo "RESOLVED=$resolved" >> "$GITHUB_ENV"

- name: Open a pull request
env:
GH_TOKEN: ${{ github.token }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
if [ -z "$(git status --porcelain)" ]; then echo "The catalog already points $NAME at $TAG"; exit 0; fi
branch="sync/$NAME-$TAG"
if git ls-remote --exit-code --heads origin "$branch" > /dev/null; then echo "Branch $branch already exists"; exit 1; fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git switch -c "$branch"
git add -A -- releases.json .claude-plugin providers packages
git commit -m "chore: sync $NAME $TAG"
git push origin "$branch"
body="$(mktemp)"
{
echo "## Changes"
echo
echo "- \`releases.json\` pins \`cavi-ai/$NAME\` to \`$TAG\` (\`$RESOLVED\`)."
echo "- Every host projection of $NAME installs that release: the Claude marketplace source, each discovery install command and, when the plugin ships one, the vendored Codex package."
echo
echo "## Verification"
echo
echo "- \`node --test\` and \`node scripts/validate-catalog.mjs\` passed in $RUN_URL."
} > "$body"
gh pr create --base main --head "$branch" --title "chore: sync $NAME $TAG" --body-file "$body"
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@

The machine-readable source of truth is [`catalog.json`](catalog.json). Claude and Codex consume native marketplace projections. Agy, OpenCode, OpenClaw, and Hermes use the discovery records under `providers/`, which link to each source repository's tested installer; those files do not claim a native marketplace protocol. Portable AgentSkills packages remain available from each plugin repository.

## Releases

[`releases.json`](releases.json) pins each released plugin to one tag and commit, and every host installs that release: the Claude marketplace source carries the tag as `ref` and the commit as `sha`, each discovery install command clones the tag, and the Codex package is copied from it. `loop-killer` has no release yet, so its Claude source follows the default branch.

A plugin's release workflow sends a `cavi-oss-release` dispatch. [Sync plugin release](.github/workflows/sync-plugin-release.yml) checks out the tag, confirms it resolves to the released commit, points every host at it with `scripts/sync-release.mjs`, runs the catalog gate and opens a pull request. The same workflow runs by hand from the Actions tab with a plugin name and tag. Locally:

```sh
node scripts/sync-release.mjs --name mlx-agent --source <checkout at the tag> --tag <release tag> --commit <full commit>
node --test && node scripts/validate-catalog.mjs
```

## Claude Code

Add the marketplace, then install a plugin:
Expand All @@ -33,16 +44,14 @@ codex plugin add mlx-agent@cavi-ai
codex plugin add obsidian-agent@cavi-ai
```

The Codex projection at [`.agents/plugins/marketplace.json`](.agents/plugins/marketplace.json) uses Codex's documented marketplace-local source layout. `packages/codex/` contains minimal, self-contained projections copied from exact upstream commits. Each package includes provenance and a deterministic tree hash; catalog validation rejects local drift.

These package projections are distribution artifacts, not independent workflow sources. Refresh one only from a reviewed upstream commit, update its `provenance.json`, and run the full catalog gate. Product development remains in the linked plugin repository.
The Codex projection at [`.agents/plugins/marketplace.json`](.agents/plugins/marketplace.json) uses Codex's documented marketplace-local source layout, so `packages/codex/` holds a self-contained copy of each release's Codex package. These copies are distribution artifacts, not independent workflow sources; product development remains in the linked plugin repository. `packages/codex/expected-integrity.json` pins each copy's release commit, tree hash and skill inventory, `provenance.json` inside the package must agree with it, and validation rejects local drift.

## Agy

Agy discovery metadata is in [`providers/agy/catalog.json`](providers/agy/catalog.json). Each entry records the source repository's native installation command:
Agy discovery metadata is in [`providers/agy/catalog.json`](providers/agy/catalog.json). Each entry records the source repository's native installation command for the pinned release:

```sh
git clone https://github.com/cavi-ai/mlx-agent.git
git clone --branch <release tag> --depth 1 https://github.com/cavi-ai/mlx-agent.git
agy plugin install ./mlx-agent/providers/agy
```

Expand All @@ -53,10 +62,10 @@ The discovery catalog itself does not install anything. `obsidian-agent` does no
OpenCode discovery metadata is in [`providers/opencode/catalog.json`](providers/opencode/catalog.json). Both source repositories provide preview-first installers:

```sh
git clone https://github.com/cavi-ai/mlx-agent.git
git clone --branch <release tag> --depth 1 https://github.com/cavi-ai/mlx-agent.git
python3 mlx-agent/scripts/mlx-agent install opencode --scope user --dry-run --json

git clone https://github.com/cavi-ai/obsidian-agent.git
git clone --branch <release tag> --depth 1 https://github.com/cavi-ai/obsidian-agent.git
node obsidian-agent/scripts/install.mjs --host opencode --scope user --dry-run
```

Expand All @@ -67,7 +76,7 @@ Review the destination paths and use the exact preview hash when confirming.
OpenClaw and Hermes discovery metadata is in [`providers/openclaw/catalog.json`](providers/openclaw/catalog.json) and [`providers/hermes/catalog.json`](providers/hermes/catalog.json). The `mlx-agent` installer places its skills in `$OPENCLAW_STATE_DIR/skills` or `$HERMES_HOME/skills`:

```sh
git clone https://github.com/cavi-ai/mlx-agent.git
git clone --branch <release tag> --depth 1 https://github.com/cavi-ai/mlx-agent.git
python3 mlx-agent/scripts/mlx-agent install openclaw --scope user --dry-run --json
python3 mlx-agent/scripts/mlx-agent install hermes --scope user --dry-run --json
```
Expand All @@ -87,4 +96,4 @@ node --test
node scripts/validate-catalog.mjs
```

Validation rejects identity drift, unknown hosts, packages for undeclared hosts, duplicate entries, non-plugin products, and projections that disagree with the canonical host list, repository, or package path.
Validation rejects identity drift, unknown hosts, packages for undeclared hosts, duplicate entries, non-plugin products, projections that disagree with the canonical host list, repository, or package path, and any host projection that does not install the plugin's pinned release.
50 changes: 46 additions & 4 deletions packages/codex/expected-integrity.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,56 @@
{
"mlx-agent": {
"repository": "cavi-ai/mlx-agent",
"source_commit": "923627988cf98e984fa36e0b940f86e7263e2958",
"source_commit": "6e6effd57bc4fce90760d938a939aef1f18e1f49",
"source_path": "providers/codex",
"tree": "c3fd7577d32e4c179d510516117a2405f80dd67e5693fd7b9835d6b84ed62d3c"
"tree": "f28e977491c286ed9b33eaae08a945daa188e899cabb1a980f84879e01351158",
"skills": [
"mlx-adopt",
"mlx-bench",
"mlx-doctor",
"mlx-fleet",
"mlx-scout",
"mlx-watch",
"mlx-wire"
]
},
"obsidian-agent": {
"repository": "cavi-ai/obsidian-agent",
"source_commit": "7efecb058fce8185056cbe7868d6de1af11879a9",
"source_commit": "b0b0cf03658b4f74c632db54834cb9add337c40a",
"source_path": ".",
"tree": "e4b9ecdc9d7d76011d955784f64d2b2f2074e5c776b5411d9fc332dd07734df2"
"tree": "b1cc6f52489f22b76d6b1700060302e11ce335ee841fa8af8ce38dcbf96c9c7a",
"skills": [
"build-retrospective",
"cloud-reply",
"connection-finder",
"consistent-tagging",
"daily-rollup",
"dedup-merge",
"frontmatter-normalizer",
"manifest-content",
"manifest-core",
"manifest-feature",
"manifest-infra",
"manifest-pm",
"manifest-research",
"manifest-risk",
"manifest-vault",
"meeting-cleanup",
"moc-builder",
"note-splitter",
"note-to-artifact",
"outline-to-draft",
"plan-to-spec",
"research-workbench",
"session-to-note",
"source-digest",
"summarize-and-link",
"task-harvester",
"tracker-driver",
"vault-grounding",
"vault-routines",
"vault-synthesis",
"wikilink-weaver"
]
}
}
4 changes: 2 additions & 2 deletions packages/codex/mlx-agent/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "mlx-agent",
"version": "0.4.0",
"version": "0.10.0",
"description": "Structured local MLX discovery, adoption, and wiring for Apple Silicon agents.",
"author": {
"name": "Sasan Sotoodehfar",
"url": "https://github.com/sasan1200"
"url": "https://cavi-ai.xyz"
},
"homepage": "https://github.com/cavi-ai/mlx-agent",
"repository": "https://github.com/cavi-ai/mlx-agent",
Expand Down
18 changes: 14 additions & 4 deletions packages/codex/mlx-agent/provenance.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
{
"repository": "cavi-ai/mlx-agent",
"source_commit": "923627988cf98e984fa36e0b940f86e7263e2958",
"source_commit": "6e6effd57bc4fce90760d938a939aef1f18e1f49",
"source_path": "providers/codex",
"included": [".codex-plugin", "skills"],
"excluded": [".mlx-agent-generated-files.json", "skills/*/scripts/mlx-agent-mcp", "skills/*/src/mlx_agent/mcp_server.py"],
"included": [
".codex-plugin",
"requirements-lab-inference.txt",
"requirements-lab.txt",
"scripts",
"skills",
"src"
],
"excluded": [
"scripts/mlx-agent-mcp",
"src/mlx_agent/mcp_server.py"
],
"exclusion_reason": "Codex skills use the packaged CLI entrypoint; MCP transport artifacts are not required or distributed by this catalog.",
"integrity": {
"algorithm": "sha256",
"tree": "c3fd7577d32e4c179d510516117a2405f80dd67e5693fd7b9835d6b84ed62d3c"
"tree": "f28e977491c286ed9b33eaae08a945daa188e899cabb1a980f84879e01351158"
}
}
10 changes: 10 additions & 0 deletions packages/codex/mlx-agent/requirements-lab-inference.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-r requirements-lab.txt
accelerate==1.15.0
diffusers==0.39.0
peft==0.21.2
protobuf==7.36.2
safetensors==0.8.0
sentencepiece==0.2.2
torch==2.14.1
torchvision==0.29.1
transformers==4.57.6
9 changes: 9 additions & 0 deletions packages/codex/mlx-agent/requirements-lab.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pydantic==2.14.0
typer==0.27.3
click==8.5.0
numpy==2.5.3
pillow==13.0.0
psutil==7.2.2
imageio==2.38.1
imageio-ffmpeg==0.6.0
huggingface-hub==0.36.2
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#!/usr/bin/env python3
"""Run the bundled MLX agent core relative to this bootstrap, never the CWD."""

import os
import sys
from pathlib import Path


sys.dont_write_bytecode = True
if sys.pycache_prefix is None:
# Compiled bytecode goes to the user cache, never into the installed plugin.
sys.pycache_prefix = str(Path(os.environ.get("XDG_CACHE_HOME") or Path.home() / ".cache").expanduser()
/ "mlx-agent" / "pycache")
SCRIPT_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(SCRIPT_DIR.parent / "src"))

Expand Down
6 changes: 3 additions & 3 deletions packages/codex/mlx-agent/skills/mlx-adopt/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ Use `$mlx-agent:mlx-adopt` to invoke this installed Codex skill explicitly. Code

# MLX Adopt

Resolve `<skill-dir>` as the absolute directory containing this SKILL.md. Never resolve the bundled executable from the shell working directory.
Resolve `<plugin-root>` as the absolute directory two levels above the directory containing this SKILL.md; it holds `scripts/` and `src/`. Never resolve the bundled executable from the shell working directory.

canonical capability ID: mlx-agent.adopt

Use the durable adoption state owned by the structured CLI. Start with a user-visible state path and requested roles:

`python3 <skill-dir>/scripts/mlx-agent adopt start --state <state-path> --role <role> --json`
`python3 <plugin-root>/scripts/mlx-agent adopt start --state <state-path> --role <role> --json`

If the state already exists or an earlier run was interrupted, continue it with:

`python3 <skill-dir>/scripts/mlx-agent adopt resume --state <state-path> --json`
`python3 <plugin-root>/scripts/mlx-agent adopt resume --state <state-path> --json`

Report the CLI state and recommendations. Do not recreate adoption policy in this adapter. This operation must not download model weights or change configuration; any later download or mutation requires explicit user confirmation and the reviewed CLI preview.

Expand Down

This file was deleted.

Loading
Loading