{"id":50387805,"url":"https://github.com/jeangnc/harness-kit","last_synced_at":"2026-05-30T16:01:27.291Z","repository":{"id":355693631,"uuid":"1229194701","full_name":"jeangnc/harness-kit","owner":"jeangnc","description":"Framework for building multi-agent harnesses — author plugins once, target every vendor (Claude Code, Codex, …).","archived":false,"fork":false,"pushed_at":"2026-05-21T18:54:26.000Z","size":461,"stargazers_count":0,"open_issues_count":7,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T03:50:38.673Z","etag":null,"topics":["agent","claude","claude-code","codex","harness","markdown","marketplace","multi-agent","plugin","skills","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeangnc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-05-04T19:51:49.000Z","updated_at":"2026-05-21T18:54:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jeangnc/harness-kit","commit_stats":null,"previous_names":["jeangnc/skill-kit"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/jeangnc/harness-kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeangnc%2Fharness-kit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeangnc%2Fharness-kit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeangnc%2Fharness-kit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeangnc%2Fharness-kit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeangnc","download_url":"https://codeload.github.com/jeangnc/harness-kit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeangnc%2Fharness-kit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33698654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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","claude","claude-code","codex","harness","markdown","marketplace","multi-agent","plugin","skills","typescript"],"created_at":"2026-05-30T16:01:26.315Z","updated_at":"2026-05-30T16:01:27.274Z","avatar_url":"https://github.com/jeangnc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Harness Kit\n\n`harness-kit` is a framework for building multi-agent harnesses — author plugins once, target every vendor.\n\n## Quickstart\n\n```sh\npnpm add @jean.gnc/harness-kit\nharness init --marketplace my-harness --vendors claude,codex\n# author src/plugins/\u003cplugin\u003e/... (see Authoring below)\nharness compile\nharness install\n```\n\n`harness` is the canonical bin; `harness-kit` is an alias.\n\n## How it works\n\n### `harness.yaml`\n\nA declarative repo config with two required fields:\n\n```yaml\nmarketplace: my-harness\nvendors:\n  - claude\n  - codex\n```\n\nCreated by `harness init`. Read automatically by `compile`, `install`, and `uninstall` via `--repo` (default `.`).\n\n### Vendors\n\nA vendor is a named target with a home directory, a per-vendor manifest path, an `emitPluginManifest` hook, `install`/`uninstall` hooks, and an optional `aliases` hook for fan-out symlink destinations. Built-in:\n\n- **claude** — registers plugins via `claude plugin install`; creates a `CLAUDE.md` symlink whenever an `AGENTS.md` config file is linked.\n- **codex** — primes the local cache by copying compiled plugins, then runs `codex plugin marketplace add`.\n\nWriting your own vendor: see [docs/vendors.md](./docs/vendors.md).\n\n### Source layout\n\n```text\nsrc/\n  \u003cvendor\u003e/configs/             # vendor-specific config files (e.g. AGENTS.md, settings.json)\n    .fragments/                 # source-only snippets; never emitted to dist (see Fragments vs companions)\n  plugins/\u003cplugin\u003e/             # shared across every declared vendor\n    .claude-plugin/plugin.json  # or PLUGIN.ts\n    skills/\u003cname\u003e/SKILL.md      # or SKILL.ts + body.md\n    agents/\u003cagent\u003e.md           # optional\n    commands/\u003ccommand\u003e.md       # optional\n    hooks/\u003chook\u003e.json           # optional\n  .claude-plugin/marketplace.json  # lists the plugins to compile\n```\n\n→ Manifest fields, passthrough behavior, and plugin extensions: [docs/marketplace.md](./docs/marketplace.md).\n\n### Compile pipeline\n\n`harness compile` reads vendors from `harness.yaml`, validates the marketplace manifest, discovers plugins, and validates each `hookRequires` against the local artifact IDs. For each declared vendor it emits everything under a single top-level `dist/\u003cvendor\u003e/` subtree:\n\n- `dist/\u003cvendor\u003e/.\u003cvendor\u003e-plugin/marketplace.json` — the per-vendor marketplace manifest.\n- `dist/\u003cvendor\u003e/plugins/\u003cplugin\u003e/` — compiled skills/agents/commands plus the per-vendor plugin manifest.\n- `dist/\u003cvendor\u003e/configs/` — vendor-specific config files (everything under `src/\u003cvendor\u003e/configs/` minus dot-prefixed entries).\n\nA top-level `dist/configs.json` link manifest enumerates the symlinks `harness install` will create.\n\n### Install pipeline\n\n`harness install` reads `harness.yaml`, then:\n\n1. Applies links from `dist/configs.json`. Existing symlinks are replaced. Regular files are renamed to `\u003cdest\u003e.backup` (incrementing to `.backup.2`, `.backup.3`, …) before the symlink is created. Orphan symlinks pointing back into the repo are swept before applying.\n2. For each declared vendor, discovers compiled plugins under `dist/\u003cvendor\u003e/plugins/` and calls the vendor's `install` hook.\n\n`--mode` selects where Claude resolves plugins from: `local` (default) registers the freshly compiled `dist/claude/` tree as a local-scoped marketplace, so uncommitted builds install without publishing; `remote` pulls from the published marketplace. Codex is local-only and ignores the flag.\n\n`--dry-run` prints the plan without touching the filesystem.\n\n## Authoring a skill\n\nSkills are auto-discovered by walking `\u003csrcRoot\u003e/plugins/\u003cplugin\u003e/skills/\u003cname\u003e/SKILL.md`. The `name` field in frontmatter must match the skill's folder name.\n\n```md\n\u003c!-- SKILL.md --\u003e\n---\nname: my-skill\ndescription: What the skill does — single line.\ncompanions:\n  - file: details.md\n    summary: Deeper notes.\n---\n\n# My Skill\n\nFor type safety conventions, see {{skill:dev-tools:typescript}}.\nFor TDD discipline, see {{skill:superpowers:test-driven-development}}.\nFor details, see {{ref:details.md}}.\n\n{{companions}}\n```\n\nCompiles to (once per declared vendor):\n\n```md\n\u003c!-- dist/\u003cvendor\u003e/plugins/\u003cplugin\u003e/skills/my-skill/SKILL.md --\u003e\n---\nname: my-skill\ndescription: What the skill does — single line.\ncompanions:\n  - file: details.md\n    summary: Deeper notes.\n---\n\n# My Skill\n\nFor type safety conventions, see `dev-tools:typescript`.\nFor TDD discipline, see `superpowers:test-driven-development`.\nFor details, see `details.md`.\n\n## Companion files (read on demand)\n\n- `details.md` — Deeper notes.\n```\n\n### Composing with includes\n\nUse `{{include:./.fragments/foo.md}}` to inline another Markdown file verbatim into the body. Includes expand recursively (an included file may itself contain `{{include:...}}`), and any other placeholders inside the inlined content are resolved against the **host skill**, not the include source.\n\nConstraints:\n\n- Path must be relative and stay inside the skill directory.\n- Target must end in `.md`.\n- Cycles are detected and fail the compile.\n- Included files are not copied into `dist/` and are not flagged as undeclared companions.\n\n### Fragments vs companions\n\nTwo kinds of secondary file appear next to skills, plugins, and configs. They have different lifecycles, so harness-kit gives them different conventions.\n\n| Kind | Lifecycle | Convention | Ships to `dist/`? |\n| --- | --- | --- | --- |\n| **Fragment** | Compile-time only — inlined via `{{include:...}}` | Leading-dot path (e.g. `.fragments/foo.md`) | No |\n| **Companion** | Runtime — read by the artifact (skill, hook, command, agent) at execution | No leading dot (e.g. `details.md`, `companions/foo.md`) | Yes |\n\n**The rule is one sentence: leading dot = source-only.** Any source file or directory whose basename starts with `.` is stripped from dist (the vendor manifest dirs like `.claude-plugin/` are still emitted because each vendor writes them separately). Everything else ships as-is.\n\nExample: a skill that inlines a shared snippet at compile time and ships a runtime companion alongside it.\n\n```text\nsrc/plugins/foo/skills/bar/\n  SKILL.md                  # uses {{include:./.fragments/snippet.md}} and references details.md\n  .fragments/snippet.md     # stripped from dist\n  details.md                # ships; consumed at runtime\n```\n\nAfter `harness compile`:\n\n```text\ndist/\u003cvendor\u003e/plugins/foo/skills/bar/\n  SKILL.md                  # snippet content inlined\n  details.md                # ships unchanged\n```\n\n### Authoring with TypeScript (alternative)\n\nIf you prefer typed metadata, use `SKILL.ts` + sibling `body.md` instead of a single `SKILL.md`:\n\n```ts\n// SKILL.ts\nimport { defineSkill } from \"@jean.gnc/harness-kit\";\n\nexport default defineSkill({\n  name: \"my-skill\",\n  description: \"What the skill does — single line.\",\n  companions: [{ file: \"details.md\", summary: \"Deeper notes.\" }],\n});\n```\n\n```md\n\u003c!-- body.md --\u003e\n# My Skill\n\nFor type safety conventions, see {{skill:dev-tools:typescript}}.\n```\n\nA skill folder must contain exactly one of `SKILL.md` or `SKILL.ts`. Both forms run through the same placeholder pipeline and produce identical `dist/` output.\n\n### Placeholder reference\n\nThree reference kinds — `skill`, `command`, `agent` — each resolve against the **local marketplace ∪ installed plugins** and render the scoped `\u003cplugin\u003e:\u003cname\u003e` handle. The author never picks a prefix based on where a target lives; a single kind covers both local and cross-plugin references.\n\nResolution is two-tier: `harness compile` resolves strictly against local artifacts and **warns** (without failing) on a reference found in neither the local marketplace nor an installed plugin — so the compile stays green on a machine without those plugins installed. `harness check --mode=all` is the hard gate: the same unresolved reference fails the check. A malformed value (not `\u003cplugin\u003e:\u003cname\u003e` shape) is always a hard error.\n\n| Placeholder | Renders to | Validation |\n| --- | --- | --- |\n| `{{skill:\u003cplugin\u003e:\u003cname\u003e}}` | `` `\u003cplugin\u003e:\u003cname\u003e` `` | Resolves against local marketplace + installed plugins; warns on compile, fails `check --mode=all` |\n| `{{command:\u003cplugin\u003e:\u003cname\u003e}}` | `` `/\u003cplugin\u003e:\u003cname\u003e` `` | Resolves against local marketplace + installed plugins; warns on compile, fails `check --mode=all` |\n| `{{agent:\u003cplugin\u003e:\u003cname\u003e}}` | `` `\u003cplugin\u003e:\u003cname\u003e` `` | Resolves against local marketplace + installed plugins; warns on compile, fails `check --mode=all` |\n| `{{ref:\u003crelative-path\u003e}}` | `` `\u003crelative-path\u003e` `` | Must be a file under the skill directory |\n| `{{include:\u003crelative-path.md\u003e}}` | Inlined content of the target file | Must be a `.md` file inside the skill, no cycles |\n| `{{companions}}` | Companion files section | Required iff companions are declared |\n\n## CLI\n\n```sh\nharness init      # scaffold harness.yaml + src/\u003cvendor\u003e/configs/ + src/plugins/\nharness compile   # compile src/ → dist/ per declared vendors\nharness lint      # lint compiled markdown under dist/\nharness check     # validate plugin references against local + installed sources\nharness install   # link configs + register plugins per declared vendor (--mode=local|remote)\nharness uninstall # remove installed plugins per declared vendor\n```\n\n→ Full flag reference, bundled lint rules, and `package.json` integration: [docs/cli.md](./docs/cli.md).\n\n## Programmatic API\n\nEverything the CLI does is also a typed module API. See [docs/api.md](./docs/api.md).\n\n## Requirements\n\n- Node ≥ 24\n- A package manager (pnpm, npm, yarn — pnpm is what this repo uses)\n- The `claude` and/or `codex` CLIs on `$PATH` — only needed to run `harness install` / `uninstall`\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeangnc%2Fharness-kit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeangnc%2Fharness-kit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeangnc%2Fharness-kit/lists"}