Metadata-Version: 2.4
Name: rolesync
Version: 1.1.0
Summary: Generate native Claude Code and Codex agent definitions from one canonical catalog.
Author: Brian Grubba
License-Expression: MIT
Project-URL: Homepage, https://github.com/ceponatia/rolesync
Project-URL: Repository, https://github.com/ceponatia/rolesync
Project-URL: Issues, https://github.com/ceponatia/rolesync/issues
Keywords: ai,agents,claude,codex,developer-tools
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# RoleSync

RoleSync keeps one canonical set of agent roles and skills under `.agents/` and renders native definitions for both Claude Code and Codex. Generated files are tracked by checksum so accidental hand-edits are detected rather than silently overwritten.

The project is intentionally a generator, not an agent runtime: it does not run a scheduler, broker credentials, enforce GitHub permissions, or provide durable background orchestration.

## Install

Python 3.11+ is required. Claude Code and Codex are optional runtime dependencies and are installed separately.

```bash
# Recommended isolated CLI install
uv tool install rolesync

# Alternative
pipx install rolesync

# One-off execution
uvx rolesync --version
```

Stable releases are published to PyPI, and `pip`, `pipx`, and `uv` install the latest one by default. Upgrade with `uv tool upgrade rolesync` or `pipx upgrade rolesync`; [CHANGELOG.md](CHANGELOG.md) lists what each release changes and any follow-up `rolesync sync` it needs.

## Quick start

```bash
rolesync init . --preset minimal --platform both
rolesync check
rolesync doctor
```

`init` refuses to replace an existing `.agents/` directory. Add `--install-root-guidance` if you want RoleSync to append a small managed block to root `AGENTS.md` and, for Claude projects, `CLAUDE.md`. Existing files are appended to rather than replaced.

Built-in presets:

- `minimal` — three generic roles (orchestrator, coder, reviewer) with no mandatory GitHub planning workflow.
- `github-workflow` — the richer example catalog shipped by this repository for issue → implementation → review → PR work. It is an opinionated starting point, not a universal policy.

Choose `--platform claude`, `--platform codex`, or `--platform both`. The selection is stored in `.agents/rolesync.json`. Projects initialized by `1.0.0rc1` or `1.0.0` that still contain `.agents/loom.json` remain supported as a legacy fallback; new projects write `.agents/rolesync.json`.

## Adopting an existing project

`init` only works on a project without `.agents/`. To bring a project that already has hand-written `.claude/agents/*.md`, `.claude/skills/*`, or `.codex/agents/*.toml` under RoleSync:

1. Create the canonical sources by hand: `.agents/catalog.json`, `.agents/common.md`, one `.agents/roles/<id>.md` per role, and `.agents/skills/<name>/` per skill. Running `rolesync init` in a scratch directory gives you a preset to copy from. Add `.agents/rolesync.json` if you want only one platform.
2. Move each hand-written agent's body into its role file and its frontmatter or TOML settings into the catalog entry. Move skills into `.agents/skills/<name>/`, keeping helper scripts and their executable bits.
3. Remove the old native files and any `.claude/skills/<name>` symlinks before the first sync. RoleSync refuses to write through a symlink and refuses to overwrite a file that is not recorded in `.agents/generated-manifest.json`; each error names the path and the remedy. Nothing is deleted or replaced for you.
4. Run `rolesync sync`, then `rolesync check`, and review the diff.
5. Commit the result. When a tracked symlink such as `.claude/skills/<name>` has become a real directory, `git commit -- <pathspec>` can fail with "does not have a commit checked out"; stage with `git add -A .agents .claude .codex` and commit the index without a pathspec.

Claude Code can run a generated agent as the main-session agent through `"agent": "<name>"` in `.claude/settings.json`. RoleSync never manages `settings.json`; set it by hand and keep that role enabled for Claude.

## Commands

```text
rolesync init [ROOT] [--preset minimal|github-workflow] [--platform both|claude|codex]
rolesync sync [--root ROOT]
rolesync check [--root ROOT]
rolesync doctor [--root ROOT]
rolesync --version
```

- `init` installs user-owned canonical sources from a built-in preset, then renders native output.
- `sync` validates the catalog and reconciles generated files.
- `check` performs the same validation/drift calculation without writing.
- `doctor` validates configuration and reports whether the selected Claude/Codex CLIs are currently on `PATH`; it does not launch paid/provider sessions.

The legacy source-tree command remains available:

```bash
python scripts/sync_agents.py
python scripts/sync_agents.py --check
```

## Canonical project layout

```text
.agents/
  catalog.json
  common.md
  rolesync.json                 optional RoleSync project settings
  policy.json               optional workflow policy; informational to the generator
  roles/<role>.md
  roles/<role>.claude.md    optional appendix rendered for one platform only (also .codex.md)
  skills/<skill>/SKILL.md
  references/*.md           optional supporting guidance
  generated-manifest.json   generated ownership/checksum record

.claude/agents/*.md          generated when Claude is enabled
.claude/skills/**            generated byte-for-byte mirrors of canonical skill resources
.codex/agents/*.toml         generated when Codex is enabled
```

Only paths recorded in the validated generated manifest are owned by RoleSync. Unrelated files under `.claude/` and `.codex/` remain untouched.

## Safety and ownership

RoleSync treats repository paths and the generated manifest as untrusted input. Managed output paths must stay inside `.claude/agents/`, `.claude/skills/`, or `.codex/agents/`; traversal and escaping symlink paths are rejected. Stale entries receive the same containment validation before deletion.

Synchronization is staged and guarded by a cross-process lock. Before applying a multi-file update, RoleSync stores recovery copies and a transaction journal. A later `sync` restores an interrupted transaction before generating new output.

Canonical skill directories may contain binary resources; they are mirrored byte-for-byte for Claude, and a helper script's executable bit is mirrored too (mode handling is skipped on Windows). `check` reports a mode-only difference as `mode:<path>`, and `sync` repairs it. Common transient files are ignored, while likely secret files such as `.env`, private keys, and PKCS#12 bundles are rejected rather than copied. This is a guardrail, not a replacement for repository secret scanning.

## Defining agents

Each catalog role supplies an internal `id`, a lowercase-kebab-case generated `name`, a `description`, a `source` under `.agents/roles/`, and `codex` and `claude` native settings. RoleSync validates required types and boundaries but intentionally does not hard-code every provider model or effort value; provider availability changes and must be verified in the installed runtime.

```json
{
  "id": "coder",
  "name": "acme-coder",
  "description": "Implement one bounded change with tests.",
  "source": ".agents/roles/coder.md",
  "skill": "acme-implement",
  "codex": {"model": "gpt-5.6-terra", "model_reasoning_effort": "medium", "sandbox_mode": "workspace-write"},
  "claude": {"model": "sonnet", "effort": "medium", "maxTurns": 40, "tools": ["Read", "Grep", "Glob", "Bash", "Edit", "Write"], "permissionMode": "default", "isolation": "worktree"}
}
```

Required: `id`, `name`, `description`, `source`, `codex.model`, `codex.model_reasoning_effort`, and `claude.model`. Everything else is optional, and omitting a key (or setting it to `null`) renders no line, so the runtime inherits its parent's setting instead of a pinned default:

- `codex.sandbox_mode`, `claude.tools`, `claude.permissionMode`, `claude.maxTurns`, `claude.effort`, and `claude.isolation` (`"worktree"` also adds a base-branch warning to the body). Omit `sandbox_mode` when a Codex worker must keep the parent's mode, for example to write under `.codex/worktrees/`.
- `skill` (one name) and `skills` (a list) name skills under `.agents/skills/`; they are merged in that order. They are preloaded through Claude's `skills:` frontmatter unless `claude.preloadSkills` is `false`, and referenced at the end of the body on both platforms as `Primary workflow: ...` (one skill) or `Workflow skills: ...` (several). A role with no skill gets neither.
- Other native Claude frontmatter passes through verbatim from the `claude` object: `disallowedTools`, `color`, `mcpServers`, `hooks`, `memory`, `background`, `initialPrompt`, and `omitClaudeMd`. Values are type-checked; unknown keys are ignored.
- `enabled: false` keeps a role in canonical sources but omits it from native output. `platforms` limits a role to `["claude"]` or `["codex"]` within the project's platform selection; use it for a Claude main-session agent that Codex has no way to run. Outputs for the dropped platform are removed as stale.
- A file named `<stem>.claude.md` or `<stem>.codex.md` next to a role source (for `roles/coder.md`, `roles/coder.claude.md`) is appended after the shared body for that platform only, for rules that differ between runtimes.

`policy.json`, role `activation` notes, and prose permissions do not become enforcement just because they are rendered. Filesystem sandboxing, connector credentials, repository protections, and runtime settings remain the actual security boundaries.

## Development and release checks

```bash
python -m unittest discover -s scripts/tests -v
python -m unittest discover -s tests -v
python scripts/sync_agents.py --check
python -m build
```

CI runs the test suites on Linux, Windows, and macOS using the minimum supported Python and the newest explicitly supported Python. It also installs the built wheel into a clean environment and exercises the CLI outside the source tree.

Releases are built by GitHub Actions and published to PyPI via Trusted Publishing through the protected `pypi` environment: publishing a GitHub Release triggers the `publish.yml` workflow, which builds and uploads the package automatically.

## Example workflow catalog

The repository's own `.agents/` catalog remains a worked example of a larger GitHub-centered team. Model routing is a starting hypothesis rather than a benchmark. The generator does not turn this example into a daemon or promise that a runtime will enforce prose-only limits.

## License

MIT — see [LICENSE](LICENSE).

Built by Brian Grubba ([@ceponatia](https://github.com/ceponatia)) at Snarebox LLC.
