Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82c6db52ad |
@@ -43,6 +43,7 @@ jobs:
|
||||
integrations-continue: ${{ steps.filter.outputs.integrations-continue }}
|
||||
integrations-cursor-cli: ${{ steps.filter.outputs.integrations-cursor-cli }}
|
||||
integrations-zcode: ${{ steps.filter.outputs.integrations-zcode }}
|
||||
integrations-agent-plugin: ${{ steps.filter.outputs.integrations-agent-plugin }}
|
||||
integrations-copilot-cli: ${{ steps.filter.outputs.integrations-copilot-cli }}
|
||||
integrations-crewai: ${{ steps.filter.outputs.integrations-crewai }}
|
||||
integrations-litellm: ${{ steps.filter.outputs.integrations-litellm }}
|
||||
@@ -194,6 +195,8 @@ jobs:
|
||||
- 'hindsight-integrations/zed/**'
|
||||
integrations-zcode:
|
||||
- 'hindsight-integrations/zcode/**'
|
||||
integrations-agent-plugin:
|
||||
- 'hindsight-integrations/agent-plugin/**'
|
||||
integrations-n8n:
|
||||
- 'hindsight-integrations/n8n/**'
|
||||
integrations-zapier:
|
||||
@@ -796,6 +799,29 @@ jobs:
|
||||
working-directory: ./hindsight-integrations/zcode
|
||||
run: uv run pytest tests -v
|
||||
|
||||
test-agent-plugin-integration:
|
||||
needs: [detect-changes]
|
||||
if: >-
|
||||
(github.event_name == 'workflow_dispatch' ||
|
||||
needs.detect-changes.outputs.integrations-agent-plugin == 'true' ||
|
||||
needs.detect-changes.outputs.ci == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || '' }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version-file: ".python-version"
|
||||
|
||||
- name: Validate Agent Plugin manifests
|
||||
working-directory: ./hindsight-integrations/agent-plugin
|
||||
run: python3 validate.py
|
||||
|
||||
build-ai-sdk-integration:
|
||||
needs: [detect-changes]
|
||||
if: >-
|
||||
@@ -5217,6 +5243,7 @@ jobs:
|
||||
- test-codex-integration
|
||||
- test-cursor-cli-integration
|
||||
- test-zcode-integration
|
||||
- test-agent-plugin-integration
|
||||
- build-ai-sdk-integration
|
||||
- test-ai-sdk-integration-deno
|
||||
- test-opencode-integration
|
||||
|
||||
@@ -50,6 +50,9 @@ INTEGRATIONS: dict[str, IntegrationMeta] = {
|
||||
"nemoclaw": IntegrationMeta("@vectorize-io/hindsight-nemoclaw", "NemoClaw"),
|
||||
"strands": IntegrationMeta("hindsight-strands", "Strands"),
|
||||
"claude-code": IntegrationMeta("hindsight-memory", "Claude Code"),
|
||||
# Git-distributed plugin bundle (Agent Plugins standard), not a registry
|
||||
# package — its changelog links to the source tree (see _package_url).
|
||||
"agent-plugin": IntegrationMeta("hindsight-agent-plugin", "Agent Plugins"),
|
||||
"zcode": IntegrationMeta("hindsight-zcode", "ZCode"),
|
||||
"claude-agent-sdk": IntegrationMeta("hindsight-claude-agent-sdk", "Claude Agent SDK"),
|
||||
"llamaindex": IntegrationMeta("hindsight-llamaindex", "LlamaIndex"),
|
||||
@@ -657,8 +660,10 @@ def _get_package_name(integration: str) -> str:
|
||||
|
||||
|
||||
def _package_url(integration: str, package_name: str) -> str:
|
||||
if integration == "claude-code":
|
||||
return "https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/claude-code"
|
||||
# Git-distributed plugin bundles have no npm/pypi package — link to the
|
||||
# source tree instead of a registry page.
|
||||
if integration in ("claude-code", "agent-plugin"):
|
||||
return f"https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/{integration}"
|
||||
if package_name.startswith("@"):
|
||||
return f"https://www.npmjs.com/package/{package_name}"
|
||||
return f"https://pypi.org/project/{package_name}/"
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
title: "Agent Plugins Persistent Memory with Hindsight | Integration Guide"
|
||||
description: "Give any Agent Plugins client — Codex, Cursor, GitHub Copilot, Kiro, VS Code — long-term memory with Hindsight. One portable, standards-based plugin bundles the Hindsight MCP server and a memory skill for recall, retain, and reflect."
|
||||
---
|
||||
|
||||
# Agent Plugins
|
||||
|
||||
Portable long-term memory for any [Agent Plugins](https://agent-plugins.org) client, powered by [Hindsight](https://vectorize.io/hindsight).
|
||||
|
||||
[Agent Plugins](https://agent-plugins.org) is the vendor-neutral open standard (developed with Amazon, Cursor, Microsoft, OpenAI, and Vercel) for packaging **Agent Skills + MCP servers** into a single distributable plugin. Instead of a separate integration per tool, Hindsight ships **one** plugin that every compatible client can load — at launch: **ChatGPT / Codex, Cursor, GitHub Copilot, Kiro, and VS Code**.
|
||||
|
||||
## Quick Start
|
||||
|
||||
:::tip Recommended: Hindsight Cloud
|
||||
[Sign up free](https://ui.hindsight.vectorize.io/signup) for a Hindsight Cloud API key — no self-hosting, no local daemon to manage.
|
||||
:::
|
||||
|
||||
1. Get your `hsk_...` API key from [ui.hindsight.vectorize.io/connect](https://ui.hindsight.vectorize.io/connect).
|
||||
2. Set the environment variables the plugin reads:
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_KEY="hsk_your_token"
|
||||
export HINDSIGHT_BANK_ID="my-project" # optional; defaults to "default"
|
||||
```
|
||||
|
||||
3. Install the plugin in your client (through its plugin/MCP UI, or by pointing it at the plugin directory — installation is client-specific per the standard).
|
||||
|
||||
Once installed, ask the agent something that depends on past context, or tell it a durable preference — it calls `recall` and `retain` automatically, guided by the bundled skill.
|
||||
|
||||
## What's in the plugin
|
||||
|
||||
The plugin is a thin, transport-only wrapper — all memory logic stays server-side in Hindsight. It follows the Agent Plugins `1.0.0` layout:
|
||||
|
||||
```
|
||||
agent-plugin/
|
||||
├── plugin.json # manifest ($schema + name + metadata)
|
||||
├── mcp.json # Hindsight MCP server (Streamable HTTP)
|
||||
└── skills/
|
||||
└── hindsight-memory/
|
||||
└── SKILL.md # teaches the agent when to recall / retain / reflect
|
||||
```
|
||||
|
||||
- **`mcp.json`** connects the client to Hindsight's built-in [MCP server](/developer/mcp-server) over Streamable HTTP.
|
||||
- **`skills/hindsight-memory/SKILL.md`** is loaded into the agent's context so it knows *when* to reach for memory, not just that the tools exist.
|
||||
|
||||
## Memory tools
|
||||
|
||||
Via the MCP server, the agent gets Hindsight's full memory surface. The three it reaches for most:
|
||||
|
||||
| Tool | When | What it does |
|
||||
|------|------|--------------|
|
||||
| `recall` | Before answering, when past context could help | Semantic + keyword + graph + temporal retrieval over the bank |
|
||||
| `retain` | After learning a durable, reusable fact | Stores the fact for future sessions |
|
||||
| `reflect` | When a lookup is too shallow and you need synthesized reasoning | Disposition-aware reasoning over everything remembered |
|
||||
|
||||
Additional tools (knowledge pages, mental models, documents, tags) are exposed too — see the [MCP Server reference](/developer/mcp-server).
|
||||
|
||||
## Configuration
|
||||
|
||||
The plugin reads two environment variables, interpolated into `mcp.json`:
|
||||
|
||||
| Setting | Env Var | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| API key | `HINDSIGHT_API_KEY` | — | Your `hsk_...` key. Sent as `Authorization: Bearer`. Required for Hindsight Cloud. |
|
||||
| Memory bank | `HINDSIGHT_BANK_ID` | `default` | Bank to read from and write to (sent as `X-Bank-Id`). Use one bank per user, project, or team for isolation. |
|
||||
|
||||
:::note Env-var syntax varies by client
|
||||
Most clients substitute `${VAR}`; some (VS Code, Cursor) use `${env:VAR}`. If your client doesn't interpolate, paste the literal key and bank id into `mcp.json`.
|
||||
:::
|
||||
|
||||
**Self-hosting:** replace the host in `mcp.json` (`https://api.hindsight.vectorize.io`) with your deployment's URL. A local server with the MCP endpoint open needs no API key.
|
||||
|
||||
## Explicit tools vs. automatic capture
|
||||
|
||||
Agent Plugins `1.0.0` standardizes **Skills + MCP**, not session lifecycle hooks. This plugin therefore delivers **explicit, tool-driven** memory that works identically across every supported client.
|
||||
|
||||
For the fully automatic experience — recall injected before every prompt and transcripts retained on session end — use the native, hook-based integration built for your specific tool, such as [Claude Code](/sdks/integrations/claude-code) or [Codex](/sdks/integrations/codex). Both share the same Hindsight banks, so memory captured by the hook-based integration is recalled through the Agent Plugin, and vice versa.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**No memories recalled**: `recall` returns results only after something has been retained. Retain a fact first, or seed the bank via the [API](/developer/api/quickstart).
|
||||
|
||||
**401 Unauthorized**: Check `HINDSIGHT_API_KEY` is set and your client is interpolating it into the `Authorization` header (see the env-var syntax note above).
|
||||
|
||||
**Wrong or empty memory**: Confirm `HINDSIGHT_BANK_ID` points at the bank you expect. Different tools writing to different banks won't share memory.
|
||||
|
||||
## Learn more
|
||||
|
||||
- [Agent Plugins standard](https://agent-plugins.org)
|
||||
- [Hindsight MCP Server reference](/developer/mcp-server)
|
||||
- [Hindsight Cloud sign-up](https://ui.hindsight.vectorize.io/signup)
|
||||
@@ -1,5 +1,15 @@
|
||||
{
|
||||
"integrations": [
|
||||
{
|
||||
"id": "agent-plugin",
|
||||
"name": "Agent Plugins",
|
||||
"description": "Portable long-term memory for any Agent Plugins client (Codex, Cursor, GitHub Copilot, Kiro, VS Code). One standards-based plugin bundles Hindsight's MCP server and a memory skill — recall, retain, and reflect everywhere.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "tool",
|
||||
"link": "/sdks/integrations/agent-plugin",
|
||||
"icon": "/img/icons/mcp.png"
|
||||
},
|
||||
{
|
||||
"id": "coding-agents",
|
||||
"name": "Coding Agents",
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Hindsight — Agent Plugin
|
||||
|
||||
A portable [Agent Plugin](https://agent-plugins.org) (spec `1.0.0`) that gives any
|
||||
compatible agent client long-term memory via [Hindsight](https://hindsight.vectorize.io).
|
||||
|
||||
Agent Plugins is the vendor-neutral standard (AWS, Cursor, GitHub/Microsoft, OpenAI,
|
||||
Vercel) for packaging **Agent Skills + MCP servers** into one distributable plugin. At
|
||||
launch it is supported by **ChatGPT/Codex, Cursor, GitHub Copilot, Kiro, and VS Code**.
|
||||
|
||||
This is the *portable* front door to Hindsight: one artifact, every supported client. It
|
||||
carries the same `retain` / `recall` / `reflect` memory as our per-IDE integrations, but
|
||||
as a single standards-based bundle instead of N hand-rolled configs.
|
||||
|
||||
## What's in the bundle
|
||||
|
||||
```
|
||||
agent-plugin/
|
||||
├── plugin.json # manifest ($schema + name + metadata)
|
||||
├── mcp.json # Hindsight MCP server (Streamable HTTP)
|
||||
└── skills/
|
||||
└── hindsight-memory/
|
||||
└── SKILL.md # teaches the agent when to recall/retain/reflect
|
||||
```
|
||||
|
||||
- **`mcp.json`** points the client at Hindsight's built-in MCP server (retain, recall,
|
||||
reflect, knowledge pages, and more — see [MCP Server docs](https://hindsight.vectorize.io/developer/mcp-server)).
|
||||
The plugin is transport-only; all memory logic stays server-side.
|
||||
- **`skills/hindsight-memory/SKILL.md`** is loaded into the agent's context so it knows
|
||||
*when* to reach for memory, not just that the tools exist.
|
||||
|
||||
## Configuration
|
||||
|
||||
The plugin reads two environment variables (values are interpolated into `mcp.json`):
|
||||
|
||||
| Variable | Required | Purpose |
|
||||
|----------|----------|---------|
|
||||
| `HINDSIGHT_API_KEY` | yes (Cloud) | Your `hsk_...` key from [ui.hindsight.vectorize.io/connect](https://ui.hindsight.vectorize.io/connect). Sent as `Authorization: Bearer`. |
|
||||
| `HINDSIGHT_BANK_ID` | no | Memory bank to scope to (sent as `X-Bank-Id`). Defaults to `default`. Use one bank per user/project/team. |
|
||||
|
||||
**Self-hosting:** replace the host in `mcp.json` (`https://api.hindsight.vectorize.io`)
|
||||
with your deployment's URL. A local server with the MCP endpoint open needs no API key.
|
||||
|
||||
> Env-var interpolation syntax varies by client. Most use `${VAR}`; some (VS Code,
|
||||
> Cursor) prefer `${env:VAR}`. If your client doesn't substitute, paste the literal key
|
||||
> and bank id into `mcp.json` instead.
|
||||
|
||||
## Install
|
||||
|
||||
Installation and distribution are intentionally left to each client by the spec. Common
|
||||
paths:
|
||||
|
||||
- **VS Code / GitHub Copilot / Cursor / Kiro** — add this plugin directory through the
|
||||
client's plugin/MCP UI, or drop it where the client discovers plugins, then set the
|
||||
two environment variables above.
|
||||
- **Codex / ChatGPT** — register the plugin per the client's Agent Plugins support.
|
||||
|
||||
Once installed, ask the agent something that depends on past context (or tell it a
|
||||
durable preference) and it will call `recall` / `retain` automatically, guided by the
|
||||
skill.
|
||||
|
||||
## Want automatic capture (hooks)?
|
||||
|
||||
Agent Plugins `1.0.0` standardizes **Skills + MCP**, not session lifecycle hooks. This
|
||||
plugin therefore delivers **explicit, tool-driven** memory that works identically
|
||||
everywhere. For the fully automatic experience — recall injected before every prompt and
|
||||
transcripts retained on session end — use the native, hook-based integration for your
|
||||
tool (e.g. [`hindsight-integrations/claude-code`](../claude-code)). The two share the
|
||||
same banks, so memory captured by one is recalled by the other.
|
||||
|
||||
## Validate the manifests
|
||||
|
||||
```bash
|
||||
python3 hindsight-integrations/agent-plugin/validate.py
|
||||
```
|
||||
|
||||
Checks that `plugin.json` and `mcp.json` parse and satisfy the Agent Plugins `1.0.0`
|
||||
required-field contract.
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
|
||||
"mcpServers": {
|
||||
"hindsight": {
|
||||
"type": "streamable-http",
|
||||
"url": "https://api.hindsight.vectorize.io/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${HINDSIGHT_API_KEY}",
|
||||
"X-Bank-Id": "${HINDSIGHT_BANK_ID}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
||||
"name": "hindsight",
|
||||
"version": "1.0.0",
|
||||
"description": "Long-term memory for AI agents. Recalls relevant past context before you answer and retains durable facts as you work, backed by Hindsight's retain/recall/reflect memory engine.",
|
||||
"author": {
|
||||
"name": "Hindsight (Vectorize)",
|
||||
"url": "https://hindsight.vectorize.io"
|
||||
},
|
||||
"homepage": "https://hindsight.vectorize.io",
|
||||
"repository": "https://github.com/vectorize-io/hindsight",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"memory",
|
||||
"long-term-memory",
|
||||
"recall",
|
||||
"retain",
|
||||
"reflect",
|
||||
"mcp",
|
||||
"agent-memory"
|
||||
],
|
||||
"extensions": {
|
||||
"io.vectorize.hindsight": {
|
||||
"bankSelection": "Set HINDSIGHT_BANK_ID to scope memory to a user, project, or team. The mcp.json endpoint is per-bank, so tools never need a bank_id argument.",
|
||||
"selfHosted": "Point HINDSIGHT_MCP_URL at your own deployment instead of Hindsight Cloud; the plugin is transport-only and stays otherwise identical.",
|
||||
"deepIntegration": "For automatic capture/injection (session hooks that recall before each prompt and retain transcripts on exit), see the native Claude Code plugin at hindsight-integrations/claude-code. This portable plugin exposes the same memory via explicit MCP tools."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
name: hindsight-memory
|
||||
description: Long-term memory for the agent via Hindsight. Use to recall relevant past context before answering, retain durable facts as you learn them, and reflect over accumulated memory for the "why" behind a decision. Load whenever continuity across sessions matters — the user refers to earlier work, states a lasting preference, or asks a question that prior context could answer.
|
||||
---
|
||||
|
||||
# Hindsight long-term memory
|
||||
|
||||
This plugin connects the agent to **Hindsight**, a long-term memory engine. Memory
|
||||
persists across sessions in a **bank** (scoped by `HINDSIGHT_BANK_ID`), so what you
|
||||
retain now is available to recall in future conversations.
|
||||
|
||||
The `hindsight` MCP server exposes the tools below. Prefer these over guessing from
|
||||
scratch when the answer might live in past context.
|
||||
|
||||
## When to recall (read memory)
|
||||
|
||||
Call **`recall`** at the start of a task, or whenever the user:
|
||||
|
||||
- refers to earlier work, a past decision, or "the thing we set up",
|
||||
- states a preference or constraint that may already be recorded,
|
||||
- asks a question that accumulated project/user context could answer.
|
||||
|
||||
```
|
||||
recall(query: "how do we deploy the API and which region")
|
||||
```
|
||||
|
||||
`recall` runs semantic + keyword + graph + temporal retrieval and returns the most
|
||||
relevant memories. Ground your answer in what comes back, and say when nothing
|
||||
relevant was found rather than inventing continuity.
|
||||
|
||||
## When to retain (write memory)
|
||||
|
||||
Call **`retain`** when you learn something **durable and reusable** — worth having in
|
||||
a future session, not just this one:
|
||||
|
||||
- stable user preferences ("prefers pnpm; deploys from `main` only"),
|
||||
- project facts and decisions ("staging DB is Postgres 16 on Neon"),
|
||||
- outcomes and gotchas ("the flaky test was a timezone bug, fixed in #482").
|
||||
|
||||
```
|
||||
retain(content: "The user deploys the API to us-east-1 via GitHub Actions on push to main.")
|
||||
```
|
||||
|
||||
Do **not** retain transient chatter, secrets, or anything the user asked you to keep
|
||||
out of memory. Retain the fact, not the whole transcript.
|
||||
|
||||
## When to reflect (reason over memory)
|
||||
|
||||
Call **`reflect`** when a single recall is too shallow and you need synthesized
|
||||
reasoning over everything remembered — the *why* behind a behavior, or a judgment that
|
||||
weighs many facts together:
|
||||
|
||||
```
|
||||
reflect(query: "What has repeatedly caused our CI to flake, and what should we standardize?")
|
||||
```
|
||||
|
||||
`reflect` is slower and disposition-aware; use it deliberately, not for lookups.
|
||||
|
||||
## Bank scope
|
||||
|
||||
All tools operate on the bank selected by the connection (`HINDSIGHT_BANK_ID`, default
|
||||
`default`). One bank = one memory store — keep a project's or a user's memory in its
|
||||
own bank so context stays isolated and relevant. You never pass a bank id to a tool;
|
||||
it is implicit from the endpoint.
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate this Agent Plugin against the Agent Plugins 1.0.0 required-field contract.
|
||||
|
||||
Config-only plugin (no runtime code to unit-test), so the meaningful check is that the
|
||||
manifests parse and satisfy the spec's structural requirements. Runs as a script
|
||||
(`python3 validate.py`) and is imported by CI as a pytest.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
PLUGIN_DIR = Path(__file__).resolve().parent
|
||||
SPEC = "1.0.0"
|
||||
PLUGIN_SCHEMA = f"https://agent-plugins.org/schemas/{SPEC}/plugin.schema.json"
|
||||
MCP_SCHEMA = f"https://agent-plugins.org/schemas/{SPEC}/mcp.schema.json"
|
||||
|
||||
# https://agent-plugins.org/schemas/1.0.0/plugin.schema.json — name pattern
|
||||
NAME_RE = re.compile(r"^(?!.*(?:--|\.\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$")
|
||||
AUTHOR_KEYS = {"name", "email", "url"}
|
||||
SERVER_TYPES = {"stdio", "streamable-http", "sse"}
|
||||
|
||||
|
||||
def _load(name: str) -> dict:
|
||||
return json.loads((PLUGIN_DIR / name).read_text())
|
||||
|
||||
|
||||
def validate_plugin_manifest() -> None:
|
||||
m = _load("plugin.json")
|
||||
assert m.get("$schema") == PLUGIN_SCHEMA, f"plugin.json $schema must be {PLUGIN_SCHEMA}"
|
||||
name = m.get("name")
|
||||
assert isinstance(name, str) and 1 <= len(name) <= 64, "name must be a 1-64 char string"
|
||||
assert NAME_RE.match(name), f"name {name!r} violates the Agent Plugins name pattern"
|
||||
author = m.get("author")
|
||||
if author is not None:
|
||||
assert isinstance(author, dict), "author must be an object"
|
||||
assert set(author).issubset(AUTHOR_KEYS), f"author allows only {AUTHOR_KEYS}"
|
||||
extensions = m.get("extensions")
|
||||
if extensions is not None:
|
||||
assert isinstance(extensions, dict), "extensions must be an object"
|
||||
for key in extensions:
|
||||
assert "." in key, f"extension namespace {key!r} must be reverse-domain"
|
||||
|
||||
|
||||
def validate_mcp_manifest() -> None:
|
||||
m = _load("mcp.json")
|
||||
assert m.get("$schema") == MCP_SCHEMA, f"mcp.json $schema must be {MCP_SCHEMA}"
|
||||
servers = m.get("mcpServers")
|
||||
assert isinstance(servers, dict) and servers, "mcp.json needs a non-empty mcpServers object"
|
||||
for server_name, server in servers.items():
|
||||
stype = server.get("type")
|
||||
assert stype in SERVER_TYPES, f"{server_name}: type must be one of {SERVER_TYPES}"
|
||||
if stype == "stdio":
|
||||
assert server.get("command"), f"{server_name}: stdio server requires command"
|
||||
else: # streamable-http | sse
|
||||
assert server.get("url"), f"{server_name}: {stype} server requires url"
|
||||
headers = server.get("headers", {})
|
||||
assert all(isinstance(v, str) for v in headers.values()), (
|
||||
f"{server_name}: header values must be strings"
|
||||
)
|
||||
|
||||
|
||||
def validate_skills() -> None:
|
||||
skills_dir = PLUGIN_DIR / "skills"
|
||||
assert skills_dir.is_dir(), "skills/ directory is missing"
|
||||
skill_files = list(skills_dir.glob("*/SKILL.md"))
|
||||
assert skill_files, "expected at least one skills/<name>/SKILL.md"
|
||||
for skill in skill_files:
|
||||
text = skill.read_text()
|
||||
assert text.startswith("---"), f"{skill} must open with YAML frontmatter"
|
||||
assert "name:" in text and "description:" in text, (
|
||||
f"{skill} frontmatter needs name and description"
|
||||
)
|
||||
|
||||
|
||||
def test_plugin_manifest() -> None:
|
||||
validate_plugin_manifest()
|
||||
|
||||
|
||||
def test_mcp_manifest() -> None:
|
||||
validate_mcp_manifest()
|
||||
|
||||
|
||||
def test_skills() -> None:
|
||||
validate_skills()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
for check in (validate_plugin_manifest, validate_mcp_manifest, validate_skills):
|
||||
check()
|
||||
print(f"ok: {check.__name__}")
|
||||
print("Agent Plugin is valid against Agent Plugins 1.0.0 required fields.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -13,7 +13,7 @@ print_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
print_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
VALID_INTEGRATIONS=("ag2" "agent-framework" "agentcore" "agno" "aider" "ai-sdk" "autogen" "chat" "claude-agent-sdk" "claude-code" "cline" "cloudflare-oauth-proxy" "coding-agents" "codex" "composio" "continue" "copilot-cli" "crewai" "cursor" "cursor-cli" "devin-desktop" "dify" "eve" "flowise" "gemini-spark" "github-copilot" "google-adk" "haystack" "langgraph" "litellm" "llamaindex" "n8n" "nemoclaw" "obsidian" "omo" "openai-agents" "openclaw" "opencode" "openhands" "paperclip" "pipecat" "pydantic-ai" "roo-code" "smolagents" "strands" "superagent" "vapi" "zcode" "zed")
|
||||
VALID_INTEGRATIONS=("ag2" "agent-framework" "agent-plugin" "agentcore" "agno" "aider" "ai-sdk" "autogen" "chat" "claude-agent-sdk" "claude-code" "cline" "cloudflare-oauth-proxy" "coding-agents" "codex" "composio" "continue" "copilot-cli" "crewai" "cursor" "cursor-cli" "devin-desktop" "dify" "eve" "flowise" "gemini-spark" "github-copilot" "google-adk" "haystack" "langgraph" "litellm" "llamaindex" "n8n" "nemoclaw" "obsidian" "omo" "openai-agents" "openclaw" "opencode" "openhands" "paperclip" "pipecat" "pydantic-ai" "roo-code" "smolagents" "strands" "superagent" "vapi" "zcode" "zed")
|
||||
|
||||
usage() {
|
||||
print_error "Usage: $0 <integration> <version>"
|
||||
@@ -58,6 +58,8 @@ get_current_version() {
|
||||
grep '"version"' "$dir/package.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'
|
||||
elif [ -f "$dir/.claude-plugin/plugin.json" ]; then
|
||||
grep '"version"' "$dir/.claude-plugin/plugin.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'
|
||||
elif [ -f "$dir/plugin.json" ]; then
|
||||
grep '"version"' "$dir/plugin.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'
|
||||
elif [ -f "$dir/settings.json" ] && grep -q '"version"' "$dir/settings.json"; then
|
||||
grep '"version"' "$dir/settings.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'
|
||||
else
|
||||
@@ -155,6 +157,10 @@ elif [ -f "$INTEGRATION_DIR/.claude-plugin/plugin.json" ]; then
|
||||
print_info "Updating version in $INTEGRATION_DIR/.claude-plugin/plugin.json"
|
||||
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$INTEGRATION_DIR/.claude-plugin/plugin.json"
|
||||
rm "$INTEGRATION_DIR/.claude-plugin/plugin.json.bak"
|
||||
elif [ -f "$INTEGRATION_DIR/plugin.json" ]; then
|
||||
print_info "Updating version in $INTEGRATION_DIR/plugin.json"
|
||||
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$INTEGRATION_DIR/plugin.json"
|
||||
rm "$INTEGRATION_DIR/plugin.json.bak"
|
||||
elif [ -f "$INTEGRATION_DIR/settings.json" ] && grep -q '"version"' "$INTEGRATION_DIR/settings.json"; then
|
||||
print_info "Updating version in $INTEGRATION_DIR/settings.json"
|
||||
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$INTEGRATION_DIR/settings.json"
|
||||
|
||||
Reference in New Issue
Block a user