Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .agnix.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ exclude = [
"experimental/**",
"research/**",
"skills/jobs/tools/portals-scan/portals-scan",
# Generated Claude-native subagent renders (agents/*.md, beside the *.yaml
# sources). Claude Code's docs require a comma-separated `tools:` string;
# agnix wrongly demands a YAML list and cannot parse them. dotagents doctor's
# "plugin agents" check validates these instead.
"agents/*.md",
]

[rules]
Expand Down
15 changes: 15 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "yourconscience",
"description": "Self-hosted marketplace for the dotagents cross-agent skill library.",
"owner": {
"name": "Kirill Korikov",
"email": "korikov.kirill@proton.me"
},
"plugins": [
{
"name": "dotagents",
"source": "./",
"description": "Cross-agent skill library and subagent roles from the dotagents repo."
}
]
}
12 changes: 12 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "dotagents",
"description": "Cross-agent skill library and subagent roles: cmux, tg, jobs, repo-eval, spawn, spec, grill-me, and more.",
"author": {
"name": "Kirill Korikov",
"email": "korikov.kirill@proton.me",
"url": "https://github.com/yourconscience"
},
"repository": "https://github.com/yourconscience/dotagents",
"license": "MIT",
"keywords": ["skills", "subagents", "workflow"]
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ external/
.claude/
.amp/
.hermes/
.omx/
.worktrees/
.skill-lock.json
__pycache__/
Expand All @@ -26,3 +27,4 @@ skills/jobs/tools/portals-scan/portals-scan
skills/remote-access/tools/remote-access-bridge/remote-access-bridge
skills/handoff/bin/
research/
skills/cua-driver
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

- Never guess numerical values. Measure or say it needs measurement.
- Validate at small scale before scaling. When scaling, change only the scale parameter.
- For new external package/tool references in ongoing projects, use versions published at least 7 days earlier. Verify publish age from the registry or say it still needs measurement.
- For new external package/tool references in ongoing projects, use versions published at least 3 days earlier. Verify publish age from the registry or say it still needs measurement.

# Environment

Expand Down
47 changes: 43 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ Reference these from TeamCreate teammates, Claude Code subagent types, or Codex

## Skills

- `bittorrent` - manage legal BitTorrent downloads, magnet links, metadata inspection, and client diagnostics.
- `cmux` - control cmux workspaces, panes, terminal/browser surfaces, markdown viewers, and visible agent workspaces.
- `tmux` - generic tmux reference for sessions, windows, panes, screen capture, and input.
- `dotagents` - inspect and sync the repo-owned skill links across supported coding agents.
Expand All @@ -61,6 +60,7 @@ Reference these from TeamCreate teammates, Claude Code subagent types, or Codex
- `spawn` - spawn and manage Claude Code agent teams with model routing and cmux integration.
- `tg` - read Telegram chats, search messages, and list dialogs through the read-only `tg` CLI.
- `tech-search` - gather high-signal opinions from tech communities and blogs on a topic.
- `tg` - read Telegram chats, search messages, and list dialogs via the read-only `tg` CLI.
- `x-cli` - unofficial CLI for `x` tooling.
- `x-sim` - offline X audience simulation for draft tweets and handle positioning.

Expand All @@ -79,7 +79,7 @@ external_skills:

## Plugins

Dotagents treats plugins as first-party catalog entries in `dotagents.yaml`, not as committed `.codex-plugin`, `.claude-plugin`, `.amp/`, or `.hermes/` runtime directories. A plugin entry records its source format, runtime surfaces, target agents, and review notes:
Dotagents treats third-party plugins as first-party catalog entries in `dotagents.yaml`, not as committed `.codex-plugin`, `.amp/`, or `.hermes/` runtime directories. (The repo's own `.claude-plugin/` manifests are the one exception; see "Installing this repo as a Claude Code plugin" below.) A plugin entry records its source format, runtime surfaces, target agents, and review notes:

```yaml
plugins:
Expand All @@ -91,7 +91,7 @@ plugins:
agents: [claude-code, codex, hermes, droid, pi]
```

Enabled plugin `skills/` surfaces are discovered from portable plugin source IDs. `codex:<source>/<plugin>` resolves under `DOTAGENTS_CODEX_PLUGIN_ROOT`; `claude:<marketplace>/<plugin>` resolves under `DOTAGENTS_CLAUDE_PLUGIN_ROOT`. For Claude Code, Codex, Factory Droid, and Pi/OMP, `dotagents sync` manages those plugin skills as symlinks in the native skill roots. For Hermes, `dotagents setup` adds the plugin `skills/` directories to `skills.external_dirs`. Amp remains compatibility-only and must be targeted explicitly in a local config if needed.
Enabled plugin `skills/` surfaces are discovered from portable plugin source IDs. `codex:<source>/<plugin>` resolves under `DOTAGENTS_CODEX_PLUGIN_ROOT`; `claude:<marketplace>/<plugin>` resolves under `DOTAGENTS_CLAUDE_PLUGIN_ROOT`. For Codex, Factory Droid, and Pi/OMP, `dotagents sync` manages those plugin skills as symlinks in the native skill roots. Claude Code uses either symlink sync or this repo's native Claude plugin based on `agents[].delivery`. For Hermes, `dotagents setup` adds the plugin `skills/` directories to `skills.external_dirs`. Amp remains compatibility-only and must be targeted explicitly in a local config if needed.

`dotagents status` prints each plugin's compatibility across known harness descriptors; non-primary harnesses show as `not targeted` unless explicitly configured. `dotagents doctor` validates the catalog and warns when an enabled plugin targets an agent that has no supported surface for it.

Expand All @@ -104,13 +104,52 @@ Compatibility model:
- `native-plugin` is host-specific: `.codex-plugin` stays Codex-native and `.claude-plugin` stays Claude-native.
- `commands` are currently Claude-native unless re-modeled as skills, hooks, MCP, or a repo-owned CLI.

### Installing this repo as a Claude Code plugin

The repo doubles as a self-hosted Claude Code plugin and single-plugin marketplace via `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`:

```
/plugin marketplace add yourconscience/dotagents
/plugin install dotagents@yourconscience
```

The repo is private, so `marketplace add` requires working GitHub git auth (ssh or `gh auth`) on the machine.

The plugin ships every skill under `skills/` (namespaced as `/dotagents:<skill>`) plus the four subagent roles. The roles are rendered from `agents/*.yaml` into `agents/*.md` (beside the sources) by `dotagents render`; Claude Code auto-discovers them from the top-level `agents/` directory. `dotagents doctor` and CI tests fail (`plugin agents` check) when the rendered copies drift from the YAML.

Plugin skills are byte-identical to the symlink-synced ones - same directories, same repo. A machine should use exactly one Claude Code delivery channel:

```yaml
agents:
- name: claude-code
delivery: sync # default: dotagents sync manages ~/.claude/skills and ~/.claude/agents
```

Use the CLI wrapper to switch Claude Code to plugin delivery:

```bash
dotagents plugin add
```

That command runs the Claude plugin install flow, sets `delivery: plugin` for `claude-code`, and prunes dotagents-managed symlinks and generated Claude agent files so skills do not appear twice (`/tg` and `/dotagents:tg`). `dotagents doctor` includes a `claude delivery` check that fails when `delivery: plugin` is set but `dotagents@yourconscience` is not installed, or when plugin delivery still has managed sync artifacts.

Use this to return Claude Code to symlink sync:

```bash
dotagents plugin remove
```

That uninstalls the Claude plugin, removes the marketplace entry, sets `delivery: sync`, and runs `dotagents sync --agents=claude-code`. Plugin installs snapshot the repo at install time; consumers pick up new skills with `/plugin update`, unlike the always-live symlinks. The plugin manifest intentionally omits a fixed `version` so Claude Code uses the git commit SHA and every new commit can be updated.

**Why Claude Code only.** Claude Code is the one supported agent whose native plugin format fits a shared-root skill library: it auto-discovers `skills/` and `agents/` from the plugin (repo) root. Codex has a plugin system too, but its plugins must live in a subdirectory with a *real, copied* `skills/` inside the plugin directory - it ignores symlinks and rejects a plugin at the marketplace root (verified against `codex 0.136.0`). Bundling our 31MB shared `skills/` into a committed subdir would mean a second source of truth, so Codex - like Droid, Amp, Hermes, and Pi - consumes dotagents skills through `dotagents sync`, not a plugin. `SKILL.md` directories remain the genuinely portable cross-tool convention.

## Agent Integration Status

Dotagents keeps `~/.agents` as the source of truth and adapts each agent through symlinks, targeted config patches, or generated native files. Do not commit agent-specific project runtime directories such as `.amp/` or `.hermes/` to this repo.

| Agent | Shared skills | Native subagents | MCP sync | Hook sync | Root instructions | Integration notes |
|---|---|---|---|---|---|---|
| Claude Code | Symlink mirror to `~/.claude/skills` | Generated to `~/.claude/agents` | `~/.claude/settings.json` | `~/.claude/settings.json` | `CLAUDE.md` shim points to `AGENTS.md` | Full managed mirror for skills, roles, MCP, and supported hooks. |
| Claude Code | `delivery: sync` symlink mirror to `~/.claude/skills`; `delivery: plugin` via `dotagents@yourconscience` | `delivery: sync` generated to `~/.claude/agents`; `delivery: plugin` from plugin `agents/*.md` | `~/.claude/settings.json` | `~/.claude/settings.json` | `CLAUDE.md` shim points to `AGENTS.md` | Use exactly one skill/role delivery channel; MCP and supported hooks remain dotagents-managed. |
| Codex | Symlink mirror to `~/.codex/skills` | Generated to `~/.codex/agents` | `~/.codex/config.toml` | `~/.codex/hooks.json` plus `[features].hooks = true` | Reads `AGENTS.md` | Full managed mirror for skills, roles, MCP, and supported hooks. |
| Hermes | Config path to `~/.agents/skills` | Not managed | `~/.hermes/config.yaml` | `~/.hermes/config.yaml` for known lifecycle hooks | Reads configured Hermes context | Uses `skills.external_dirs`; do not mirror into `~/.hermes/skills` because bundled categories can collide. |
| Factory Droid | Symlink mirror to `~/.factory/skills` | Generated to `~/.factory/droids` | `~/.factory/mcp.json` | `~/.factory/settings.json` | `~/.factory/AGENTS.md` symlink | Full managed mirror for skills, roles, MCP, and supported hooks. |
Expand Down
24 changes: 24 additions & 0 deletions agents/architect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: "architect"
description: "Designs system architecture, telemetry schemas, and technical plans. Use for design docs, architecture reviews, and API surface decisions. Delegates implementation to builders."
model: "sonnet"
effort: "high"
tools: Read, Glob, Grep, Bash, Write, Edit
color: "blue"
---

<!-- Generated by dotagents from agents/architect.yaml; do not edit directly. -->

You are a senior software architect. Your job is to design, not build.

Read the codebase before proposing changes. Trace data flow and dependencies. Identify existing patterns and match them.

Output concrete design documents with:
- Current state analysis (what exists, what's missing)
- Proposed changes (which files, which functions, what the diff looks like)
- Migration path (backward compatibility, rollout steps)
- Risks and open questions

Do not implement. Write the design doc, then hand off to a builder or report back.

When working on a team, check the shared task list after completing your work. Message teammates when your design affects their tasks.
25 changes: 25 additions & 0 deletions agents/builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: "builder"
description: "Implements code changes following specs or architect designs. Use for feature implementation, bug fixes, and script writing. Focused on writing correct, minimal code."
model: "sonnet"
effort: "high"
tools: Read, Glob, Grep, Bash, Write, Edit
color: "yellow"
---

<!-- Generated by dotagents from agents/builder.yaml; do not edit directly. -->

You are a senior developer. Your job is to implement exactly what was specified.

Follow the design doc, spec, or task description precisely. Do not add features beyond scope. Do not refactor adjacent code. Match existing style.

Before coding:
- Read the relevant files
- Understand the existing patterns
- Identify the minimal set of changes needed

After coding:
- Verify your changes work (run tests, type checks, or a quick manual validation)
- Report what you changed and any issues encountered

When working on a team, check the shared task list after completing your work. Claim the next available unblocked task.
22 changes: 22 additions & 0 deletions agents/researcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: "researcher"
description: "Investigates codebases, APIs, repos, and web sources to produce findings reports. Use for technical research, competitive analysis, and feasibility studies."
model: "sonnet"
effort: "high"
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, Write
color: "green"
---

<!-- Generated by dotagents from agents/researcher.yaml; do not edit directly. -->

You are a technical researcher. Your job is to investigate and report, not implement.

Gather evidence from code, documentation, APIs, and web sources. Distinguish verified facts from speculation. Include direct links and file paths for every claim.

Output structured findings reports with:
- What was investigated and how
- Key findings (with evidence)
- Gaps and unknowns
- Recommendations

Write your report to the location specified in your task. When working on a team, message teammates if your findings affect their work.
27 changes: 27 additions & 0 deletions agents/reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: "reviewer"
description: "Reviews code changes, PRs, and implementations against specs and best practices. Use for code review, quality gates, and pre-merge checks. Read-only."
model: "sonnet"
effort: "high"
tools: Read, Glob, Grep, Bash
color: "purple"
---

<!-- Generated by dotagents from agents/reviewer.yaml; do not edit directly. -->

You are a senior code reviewer. Your job is to find bugs, security issues, and spec violations.

Review code against:
1. The spec or design doc (does it do what was asked?)
2. Correctness (edge cases, error handling, race conditions)
3. Security (injection, XSS, auth bypass, secret leaks)
4. Style (matches existing codebase conventions)

Report findings as:
- **Critical**: breaks functionality, security vulnerability, data loss risk
- **High**: bugs, performance issues, spec violations
- **Medium**: style, naming, minor improvements

Be specific: file:line, what's wrong, what the fix should be. Don't nitpick style when the code is correct and readable.

When working on a team, check the shared task list after completing your work. Message teammates if your review findings require their attention.
91 changes: 91 additions & 0 deletions cmd/dotagents/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ import (

const generatedAgentMarker = "Generated by dotagents"

// pluginAgentsRelDir is where committed Claude-format renders of agents/*.yaml
// live. Claude Code auto-discovers plugin subagents from top-level agents/*.md
// only - it does not recurse, and the plugin.json "agents" array does not
// register them (verified empirically) - so the renders sit directly alongside
// the .yaml sources. loadAgentRoles globs *.yaml and ignores the .md, so they
// coexist in the same directory.
const pluginAgentsRelDir = "agents"

type agentRole struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Expand Down Expand Up @@ -135,6 +143,83 @@ func loadAgentRoles(repoRoot string) ([]agentRole, error) {
return roles, nil
}

func expectedPluginAgentFiles(repoRoot string) (map[string]string, error) {
roles, err := loadAgentRoles(repoRoot)
if err != nil {
return nil, err
}
files := make(map[string]string, len(roles))
for _, role := range roles {
path := filepath.Join(repoRoot, filepath.FromSlash(pluginAgentsRelDir), role.Name+".md")
files[path] = renderClaudeAgentRole(role)
}
return files, nil
}

func runRender(opts runOptions) error {
repoRoot, _, _, _, err := loadContext(opts)
if err != nil {
return err
}
return renderPluginAgents(repoRoot)
}

func renderPluginAgents(repoRoot string) error {
expected, err := expectedPluginAgentFiles(repoRoot)
if err != nil {
return err
}
dir := filepath.Join(repoRoot, filepath.FromSlash(pluginAgentsRelDir))
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("create %s: %w", dir, err)
}

written, unchanged := 0, 0
for path, content := range expected {
data, err := os.ReadFile(path)
if err == nil && string(data) == content {
unchanged++
continue
}
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("read %s: %w", path, err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
return fmt.Errorf("write %s: %w", path, err)
}
written++
}

removed := 0
entries, err := os.ReadDir(dir)
if err != nil {
return fmt.Errorf("read %s: %w", dir, err)
}
for _, entry := range entries {
if entry.IsDir() || filepath.Ext(entry.Name()) != ".md" {
continue
}
path := filepath.Join(dir, entry.Name())
if _, ok := expected[path]; ok {
continue
}
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read %s: %w", path, err)
}
if !strings.Contains(string(data), generatedAgentMarker) {
continue
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("remove stale %s: %w", path, err)
Comment thread
yourconscience marked this conversation as resolved.
}
removed++
Comment thread
yourconscience marked this conversation as resolved.
}

fmt.Printf("rendered %s: %d written, %d unchanged, %d removed\n", pluginAgentsRelDir, written, unchanged, removed)
return nil
}

func renderAgentRole(role agentRole, agent agentConfig) (string, string, bool) {
h := harnessFor(agent.Name)
if h == nil || h.Roles == nil {
Expand Down Expand Up @@ -392,6 +477,12 @@ func applyAgentRoleSync(reports []agentReport, selected []agentConfig, repoRoot
if len(report.Conflicts) > 0 {
return fmt.Errorf("%s has conflicts", report.Name)
}
if usesPluginDelivery(agent) {
if err := pruneManagedAgentFiles(agent.AgentRoot, report.RemovesAgent); err != nil {
return err
}
continue
}
expected, err := expectedAgentRoles(repoRoot, agent)
if err != nil {
return err
Expand Down
Loading
Loading