{"id":51785151,"url":"https://github.com/synadia-ai/synadia-agents","last_synced_at":"2026-07-20T17:00:41.980Z","repository":{"id":356579161,"uuid":"1218193831","full_name":"synadia-ai/synadia-agents","owner":"synadia-ai","description":"SDKs and reference implementations for the Synadia Agent Protocol for NATS","archived":false,"fork":false,"pushed_at":"2026-07-14T14:24:07.000Z","size":3469,"stargazers_count":63,"open_issues_count":3,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-07-14T16:24:11.506Z","etag":null,"topics":["agent-protocol","ai","ai-agents","claude-code","dspy","hermes-agent","llm","multi-agent","multi-agent-system","nats","nats-io","open-agents","openclaw","pi-coding-agent","python","sdk","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/synadia-ai.png","metadata":{"files":{"readme":"README-DEV.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-22T16:18:14.000Z","updated_at":"2026-07-14T14:24:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/synadia-ai/synadia-agents","commit_stats":null,"previous_names":["synadia-ai/synadia-agents"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/synadia-ai/synadia-agents","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synadia-ai%2Fsynadia-agents","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synadia-ai%2Fsynadia-agents/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synadia-ai%2Fsynadia-agents/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synadia-ai%2Fsynadia-agents/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/synadia-ai","download_url":"https://codeload.github.com/synadia-ai/synadia-agents/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synadia-ai%2Fsynadia-agents/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35693383,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"ssl_error","status_checked_at":"2026-07-20T02:08:09.736Z","response_time":111,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-protocol","ai","ai-agents","claude-code","dspy","hermes-agent","llm","multi-agent","multi-agent-system","nats","nats-io","open-agents","openclaw","pi-coding-agent","python","sdk","typescript"],"created_at":"2026-07-20T17:00:34.004Z","updated_at":"2026-07-20T17:00:41.969Z","avatar_url":"https://github.com/synadia-ai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Local development\n\nQuick reference for working on the TypeScript packages in this repo\nwithout publishing to npm. The Python side is documented in\n[`client-sdk/python/CLAUDE.md`](client-sdk/python/CLAUDE.md).\n\nThe TypeScript SDK ships as **two npm packages** that always release in\nlockstep:\n\n| Path | Package | Role |\n| --- | --- | --- |\n| `client-sdk/typescript/` | `@synadia-ai/agents` | Caller side — discover, prompt, stream. Most consumers want only this. |\n| `agent-sdk/typescript/` | `@synadia-ai/agent-service` | Host side — `AgentService`, `ReferenceAgent`, server-side wire helpers. Depends on the caller package. |\n\nInside the monorepo every consumer (`agents/*`, `examples/*`) refers to\nboth packages via `file:` links in its `package.json`. Bun **copies**\nthose links at install time rather than symlinking, so an edit to\neither SDK is invisible to a consumer until that consumer's install is\nrefreshed against a freshly built `dist/`.\n\nThe same applies inside `agent-sdk/typescript/` itself: it depends on\n`@synadia-ai/agents` via `file:`, so its own `node_modules` carries a\ncopy of the caller package that needs caller's `dist/` to be present\nfor the host's compiled `dist/index.cjs` to load.\n\nThe recipes below all account for this.\n\n## Building the SDKs\n\nBuild caller first, then host (host depends on caller's `dist/`):\n\n```sh\n(cd client-sdk/typescript \u0026\u0026 bun run build)\n(cd agent-sdk/typescript  \u0026\u0026 bun install \u0026\u0026 bun run build)\n```\n\nThe extra `bun install` in `agent-sdk/typescript` re-copies the\nfreshly-built caller `dist/` into `agent-sdk/typescript/node_modules/@synadia-ai/agents/`,\nwhich is the path host's compiled output resolves at runtime.\n\nSkip the build commands above if neither SDK has changed since the\nlast build — but if you're unsure, rebuilding is cheap (~1s each).\n\n## Running the examples\n\nEach example has a `start` script that runs the source directly with\n`bun run`. After building the SDKs, refresh the example's install so\nits copy of each SDK reflects the latest `dist/`, then run:\n\n```sh\ncd examples/pi-headless    # or examples/claude-code-headless / examples/dspy\nbun install\nbun run start\n```\n\n`bun install` is what copies the freshly-built SDKs into the example's\n`node_modules`. Without it the example silently runs against whatever\n`dist/` was current at the previous install.\n\nFor the browser test client `examples/agent-web-ui` only the caller\nSDK matters (it doesn't host an agent), but the install dance is the\nsame.\n\n## Running the SDK-side examples\n\nBoth SDKs ship runnable example scripts next to the package source —\nuseful as smoke targets while iterating on the SDK or as starting\nshapes for new agents:\n\n| Path | What it does |\n| --- | --- |\n| `client-sdk/typescript/examples/01-discover.ts` … `05-liveness.ts` | Caller-side demos against a running agent. |\n| `client-sdk/typescript/examples/_run-reference-agent.ts` | Spec-compliant `ReferenceAgent` to point the caller demos at. |\n| `agent-sdk/typescript/examples/01-echo.ts` | Minimal `AgentService` echo agent. |\n\nEach script supports `$NATS_CONTEXT`, `$NATS_URL`, or falls back to\n`nats://127.0.0.1:4222`. Run with:\n\n```sh\nbun client-sdk/typescript/examples/_run-reference-agent.ts\nbun agent-sdk/typescript/examples/01-echo.ts\n```\n\n## Installing extension-style agent plugins locally (PI, OpenClaw, Claude Code)\n\n`agents/pi/`, `agents/openclaw/`, and `agents/claude-code/` are\nextension/plugin packages that get loaded by their host application\n(`pi`, `openclaw`, the Claude Code MCP runtime). When the host loads\nthe extension it follows the `file:` link in the extension's\n`package.json` back to the SDK source — so both SDKs need a current\n`dist/` when the extension is installed.\n\nOther agent packages in `agents/`, including `agents/flue/`,\n`agents/opencode/`, and `agents/codex/`, run as\nsidecars or wrappers rather than host-loaded extensions; follow their\nper-agent READMEs for local startup.\n\n```sh\n# Build the SDKs, then install the extension into its host application.\n(cd client-sdk/typescript \u0026\u0026 bun run build)\n(cd agent-sdk/typescript  \u0026\u0026 bun install \u0026\u0026 bun run build)\n\n# Pi:\npi install $(pwd)/agents/pi\npi\n\n# OpenClaw:\nopenclaw install $(pwd)/agents/openclaw\n\n# Claude Code (MCP plugin):\n# follow the install steps in agents/claude-code/README.md\n```\n\nIf the host complains with a path like\n`Cannot find module '.../agent-sdk/typescript/node_modules/@synadia-ai/agents/dist/index.cjs'`,\nthe missing `dist/` is in `agent-sdk/typescript/node_modules/@synadia-ai/agents/` —\nre-run the SDK build sequence above (the `bun install` step in\n`agent-sdk/typescript` is what populates that path).\n\n## Editing one SDK without rebuilding the other\n\nWhen iterating on caller-side code only:\n\n```sh\n(cd client-sdk/typescript \u0026\u0026 bun run build)\n(cd agent-sdk/typescript  \u0026\u0026 bun install)   # refresh nested caller copy\n# then refresh the consumer's install (cd to consumer dir, bun install)\n```\n\nWhen iterating on host-side code only:\n\n```sh\n(cd agent-sdk/typescript \u0026\u0026 bun run build)\n# then refresh the consumer's install\n```\n\n## Running the test suites\n\nThe TS test suites use vitest's `resolve.alias` to resolve\n`@synadia-ai/agents` and `@synadia-ai/agent-service` directly to source.\nThat bypasses `dist/` for tests, so the suites run fine without\nbuilding first:\n\n```sh\n(cd client-sdk/typescript \u0026\u0026 bun run check)   # typecheck + lint + format + tests\n(cd agent-sdk/typescript  \u0026\u0026 bun run check)\n```\n\n`bun run check` will pull in the sibling SDK's source via path aliases.\nOn a fresh clone install both packages first so the transitive\n`@nats-io/*` deps are available to both checkouts:\n\n```sh\n(cd client-sdk/typescript \u0026\u0026 bun install)\n(cd agent-sdk/typescript  \u0026\u0026 bun install)\n```\n\nCI runs the same shape — see\n[`.github/workflows/client-sdk-typescript.yml`](.github/workflows/client-sdk-typescript.yml)\nand [`.github/workflows/agent-sdk-typescript.yml`](.github/workflows/agent-sdk-typescript.yml).\n\n## Releasing the SDKs\n\n`main` keeps `file:` links between consumers and the SDK packages so\ncontributors editing the SDK see their changes live in the\nagents/examples without any flip step. That's also why a fresh `npm\npublish` of any consumer would ship `file:` refs that break for npm\nusers — published tarballs need `^semver` instead. The\n[`devtools/devmode.sh`](devtools/devmode.sh) script bridges the two\nstates.\n\n```sh\n./devtools/devmode.sh status        # what's currently flipped where\n./devtools/devmode.sh off           # flip every tracked consumer to ^semver\n./devtools/devmode.sh on            # flip back to file: (the default state)\n./devtools/devmode.sh check-release # exit 0 iff every dep is at its SDK's ^semver\n```\n\nThe script discovers consumers automatically — every `package.json`\nunder `examples/`, `agents/`, `client-sdk/`, and `agent-sdk/` that\ndepends on a tracked SDK gets flipped. Names listed in\n`devtools/.devmodeignore` are skipped (currently just `dspy`, which\nlives on `file:` permanently).\n\n### The release ladder (one cycle)\n\nOrder matters: caller `@synadia-ai/agents` first because the host SDK\ndeclares `^0.4.x` against it; agent harnesses and headless examples\nfollow once both SDKs are on npm. Each `npm publish` is a separate\nuser-approval gate — read the dry-run output before pulling the\ntrigger.\n\n```sh\n# 1. Pre-flight: confirm versions, identity, and tarball shape.\ngit status                                       # tree must be clean\njq -r '.version' client-sdk/typescript/package.json\njq -r '.version' agent-sdk/typescript/package.json\nnpm whoami                                       # the @synadia-ai publish identity\n\n# 2. Build dist/ artifacts fresh.\n(cd client-sdk/typescript \u0026\u0026 bun install \u0026\u0026 bun run build)\n(cd agent-sdk/typescript  \u0026\u0026 bun install \u0026\u0026 bun run build)\n\n# 3. Flip to release mode.\n./devtools/devmode.sh off\n\n# 4. Publish caller, then host. Inspect each dry-run before publishing.\n(cd client-sdk/typescript \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n(cd agent-sdk/typescript  \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n\n# 5. Publish each consumer that needs to ship.\n#    Bundled (agents/openclaw, agents/pi) — `bun install` first so\n#    bundleDependencies can copy the SDKs into the tarball.\n(cd agents/openclaw \u0026\u0026 bun install \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n(cd agents/pi       \u0026\u0026 bun install \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n#    Plain plugin packages with Bun TypeScript entrypoints.\n(cd agents/opencode \u0026\u0026 bun install \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n(cd agents/codex    \u0026\u0026 bun install \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n#    Plain (examples/pi-headless, examples/claude-code-headless) — the\n#    `prepack` hook builds dist/ on its own.\n(cd examples/pi-headless           \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n(cd examples/claude-code-headless  \u0026\u0026 npm publish --dry-run \u0026\u0026 npm publish)\n\n# 6. Flip back to dev mode and commit any non-empty diff.\n./devtools/devmode.sh on\ngit status\n```\n\n### Gotchas the script accounts for (so you don't trip over them)\n\n- **`agent-sdk/typescript`'s self-dep on caller.** Discovery scans\n  `agent-sdk/` and `client-sdk/` in addition to `examples/` and\n  `agents/`. Without that, the host SDK would publish with a `file:`\n  ref to caller, which breaks every npm consumer of the host.\n- **`bun install --silent` can spin on `agents/openclaw`.** Its\n  `peerDependencies: { openclaw: \"\" }` (empty version range) sends bun\n  into a 100%-CPU walk. Each per-consumer `bun install` is wrapped in\n  `timeout 60` (override with `BUN_INSTALL_TIMEOUT=…`); the script\n  prints a `⏱ timed out` line and continues.\n- **`^semver` `bun install` failures pre-publish are normal.** Before\n  the SDK pair is on npm, `devmode.sh off` flips the deps but the\n  follow-on `bun install` can't resolve `^0.4.0` against an empty\n  registry. The script treats those as best-effort; the package.json\n  flips themselves succeed and that's what `npm publish` reads.\n\n## Troubleshooting\n\n| Symptom | Likely cause | Fix |\n| --- | --- | --- |\n| `Cannot find module '@synadia-ai/agent-service'` at startup | Consumer's install is older than the host SDK split | `bun install` in the consumer dir |\n| `Cannot find module '.../agent-sdk/typescript/node_modules/@synadia-ai/agents/dist/index.cjs'` | Caller's `dist/` not present in agent-sdk's nested install | `(cd client-sdk/typescript \u0026\u0026 bun run build) \u0026\u0026 (cd agent-sdk/typescript \u0026\u0026 bun install)` |\n| Edits to SDK source aren't reflected when running an example or extension | Consumer's `node_modules` carries a stale copy | Rebuild the SDK(s) and re-`bun install` in the consumer |\n| `Failed to resolve entry for package \"@synadia-ai/agents\"` from vitest | Stale CI-style install without sibling SDK source | `bun install` in the sibling SDK directory |\n| `./devtools/devmode.sh off` hangs on `agents/openclaw` | bun's empty-string peer-dep walk | The script auto-times-out at 60 s; kill manually if you ran an older version |\n| `./devtools/devmode.sh off` reports `bun install` failures with `404` / `No version matching ^x.y.z` | Pre-publish — the SDKs aren't on npm yet | Expected; the package.json flips succeeded. Run again after `npm publish` to refresh lockfiles. |\n\n## Why not workspaces?\n\nA Bun workspace would symlink the `file:` packages and remove most of\nthe rebuild/reinstall dance, at the cost of a non-trivial restructure\n(root `package.json`, repo-wide `bun.lock`, and a publish workflow that\ncorrectly handles workspace deps). The current layout keeps each\npackage self-contained and publishable on its own.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynadia-ai%2Fsynadia-agents","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsynadia-ai%2Fsynadia-agents","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynadia-ai%2Fsynadia-agents/lists"}