Skip to content

linktogo/ai-sync

Repository files navigation

ai-sync

Tools to sync AI agent skills, practices, and workflows across repositories.

Skills are authored once under skills/<techno>/<name>/SKILL.md and translated into each target platform's format (Claude Code, GitHub Copilot, Cursor, Windsurf).

Configuration

Both commands read a JSON config (see repos.json) describing the target repos:

{
  "defaultTargets": ["claude", "copilot"],
  "repos": [
    {
      "name": "oc-be",
      "url": "https://github.com/oclair-org/oc-be.git",
      "technologies": ["nestjs", "postgres"],
      "targets": ["claude", "cursor"]
    }
  ]
}
  • repos (required): non-empty array. Each repo needs name, url, and a non-empty technologies array (matched against skills/<techno>/).
  • targets: per-repo list of output formats. Falls back to defaultTargets when omitted. Known targets: claude, copilot, cursor, windsurf.
  • url: SSH and scp-style URLs (git@host:org/repo.git, ssh://…) are rewritten to HTTPS automatically before cloning.

Usage

node bin/sync.js --config repos.json          # clone, generate, branch, commit, push
node bin/sync.js --config repos.json --pr      # also open a PR via gh
node bin/sync.js --config repos.json --dry-run # preview generated files, no git
node bin/sync.js --config repos.json --repo oc-be   # one repo only

Workspace bootstrap

Clone the repos from repos.json into a workspace folder, install dependencies (Node via pnpm, Java via mvn dependency:go-offline, detected from package.json / pom.xml), and print the command to open the workspace in Claude Code or VS Code. Installs are cache-first (pnpm --prefer-offline; Maven resolves ~/.m2 first) so a slow network stays off the critical path. Re-running against an existing folder reuses the checkouts already present (and refreshes their dependencies), so the same command both creates a new workspace and resumes an existing one.

node bin/workspace.js --config repos.json --workspace ~/work/oclair                 # clone + install, prints `cd … && claude`
node bin/workspace.js --config repos.json --workspace ~/work/oclair --editor vscode  # prints `code …`
node bin/workspace.js --config repos.json --workspace ~/work/oclair --repo oc-be     # one repo only
node bin/workspace.js --config repos.json --workspace ~/work/oclair --no-install     # skip dependency install
node bin/workspace.js --config repos.json --workspace ~/work/oclair --dry-run         # preview clone/install actions, no side effects
node bin/workspace.js --config repos.json --workspace ~/work/oclair --offline        # strict offline: fail if a dep is not already cached

Worktrees (Claude Code)

When launching Claude Code, isolate the work on a dedicated branch with --worktree <branch> (only valid with --editor claude). For each repo it runs git worktree add <repo>.<branch> next to the checkout, installs deps in the worktree, and points the launch command at it. Re-running reuses an existing worktree. Without the flag the tool prints a tip suggesting it.

node bin/workspace.js --config repos.json --workspace ~/work/oclair --worktree feat/login
# → adds oc-be.feat-login/, then: cd "~/work/oclair/oc-be.feat-login" && claude

Status tracking

Bootstrap wires each checkout to report its kanban status into a shared board.json at <workspace>/.ai-sync/board.json (the four states are todo, inprogress, question, done). It does this by merging Claude Code hooks into each repo's .claude/settings.local.json, so a running session updates the board automatically:

  • UserPromptSubmitinprogress (work resumed)
  • Notification (permission/idle prompt) → question (waiting on you)
  • Stopquestion

The hooks shell out to this CLI's status subcommand, which you can also run by hand — e.g. to mark a repo done:

node bin/workspace.js status oc-be done --board ~/work/oclair/.ai-sync/board.json
# or, if installed on PATH: ai-workspace status oc-be done --board <board.json>

The board is seeded (todo for every repo) at bootstrap and updated atomically. Hook install and seeding are skipped on --dry-run. Only repos listed in the config are tracked — a directory you create under the workspace by hand gets no hooks and never appears on the board.

To see it in the dashboard, point the server at this same file — see below.

Board dashboard

A read-only kanban dashboard (Vue 3 + Tailwind) that displays each repo's status by polling board.json every few seconds. It lives in apps/board/ as a self-contained sub-package; a tiny zero-dependency Node server (apps/board/server.js) exposes GET /api/board and serves the built front-end.

npm start builds the front-end (deps install + Vite build) and then serves it:

npm start                                     # build + serve on http://localhost:4180 (board.json in cwd)
npm start -- --board /tmp/board.json          # use a specific board file
AI_SYNC_BOARD=/tmp/board.json npm start       # board path via env instead of --flag
npm start -- --board /tmp/board.json --port 8080   # custom port
npm start -- --config repos.json              # also serve repo metadata at /api/config
npm run board:build                           # build only, without starting the server

With no --board/AI_SYNC_BOARD, the server defaults to board.json in the current directory and serves an empty board until that file exists. If the chosen port is already in use, the server falls back to the next free port (à la Angular CLI) and prints the one it settled on.

Common gotcha: the board written by Status tracking lives at <workspace>/.ai-sync/board.json, not in the current directory. To view it, start the server with --board <workspace>/.ai-sync/board.json (or set AI_SYNC_BOARD). Pointing the server at the default ./board.json is the usual reason the dashboard looks empty even though sessions are running.

board.json has the shape { version: 1, repos: { <name>: { status, updatedAt, lastEvent, events } } }, where status is one of todo, inprogress, question, done and events is a bounded (last 20, newest-first) per-repo history of { event, at } entries. The version stays 1: the events field is additive and legacy files are backfilled transparently on read. The dashboard only reads it — writers (e.g. the board.js state module) work whether or not the server is running.

Beyond the plain board, the dashboard fires a browser notification (with an optional, off-by-default sound toggle persisted in localStorage) and a tab-title badge whenever a repo transitions into question (an agent is blocked on you) or done. A summary header shows per-status counts and a done-progress bar, a filter bar narrows the board by repo name or technology, and clicking a card opens a detail side panel with the repo URL, technology/target chips, and its event timeline. When started with --config repos.json (or AI_SYNC_CONFIG), the server also exposes GET /api/config to power the links and technology filter; without it the board still runs in a degraded mode (no links/filter).

Tests

npm test          # root suite: 100% coverage gate on src/
npm run test:board # apps/board suite: server (node:test) + front-end (vitest)

About

tools to synch skill, practice, workflow

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors