AGENTS.md
This file provides guidance to coding agents - such as Claude Code, Codex, etc - when working with code in this repository.
Project Overview
agconf is a CLI utility for managing and syncing AI agent configurations (AGENTS.md, skills, instructions) across repositories from a canonical source. It solves configuration drift for teams using AI coding agents like Claude Code.
Repository Structure
This is a monorepo with the CLI package in /cli:
- Root: Git hooks setup (husky), workspace config
/cli: The main npm package (published asagconf)
Development Commands
All commands run from the /cli directory:
# Development
pnpm install # Install dependencies
pnpm start -- <command> # Run without building (e.g., pnpm start -- init --help)
pnpm dev # Watch mode
# Testing
pnpm test # Run tests
pnpm test:watch # Watch mode
pnpm test:coverage # With coverage
# Code Quality
pnpm check # Lint + format check (Biome)
pnpm check:fix # Auto-fix issues
pnpm typecheck # TypeScript type check
# Build
pnpm build # Build for distribution
pnpm install:global # Build + install globally
Architecture
Core Modules (cli/src/core/)
sync.ts- Main sync logic between canonical and downstream reposlockfile.ts- Version pinning and metadata trackingmarkers.ts- HTML comment markers for section separation in managed filesmerge.ts- AGENTS.md merge logic (preserves repo-specific content). Also handles CLAUDE.md consolidation: merges content from both root and .claude/ locations into AGENTS.md, then keeps only root CLAUDE.md with @AGENTS.md reference (deletes .claude/CLAUDE.md if present)source.ts- Resolves canonical repos (git or local paths)workflows.ts- GitHub Actions workflow generationhooks.ts- Pre-commit hook installationtargets.ts- Multi-agent target supportrules.ts- Sync modular rule files from canonical to downstream repos
Commands (cli/src/commands/)
Commands: init, sync, check, propose, upgrade-cli (with --package-manager option), canonical (init), config, completion
Reminder: When modifying command options in
cli/src/cli.ts, you MUST also updatecli/src/commands/completion.ts. See CLI Command Changes.
Utilities (cli/src/utils/)
package-manager.ts- Package manager detection for CLI upgrades (npm, pnpm, yarn, bun)
Configuration (cli/src/config/)
- Zod schemas for canonical config (
agconf.yaml) and lockfile validation
Key Patterns
- File markers: HTML comments (
<!-- agconf:global:start -->) separate global vs repo-specific content - Lockfile pinning:
.agconf/lockfile.jsontracks sync state and versions - Merge strategy: Global content updates while preserving repo-specific sections in AGENTS.md
- Target support: Multi-agent targets (Claude Code, Codex) defined in
cli/src/core/targets.ts; source resolution (GitHub repos, local paths) incli/src/core/source.ts - Downstream config:
.agconf/config.yamlin downstream repos for user preferences (workflow settings) - Default prefix: The canonical default prefix is
"agconf". When writing fallback values, always reference the defined constants (DEFAULT_MARKER_PREFIX,DEFAULT_METADATA_PREFIX) rather than hardcoding. - Prefix normalization: Marker prefixes use dashes (e.g.,
my-prefix), metadata prefixes use underscores (e.g.,my_prefix). Conversion MUST usetoMarkerPrefix()/toMetadataPrefix()fromcli/src/utils/prefix.ts. Do not use inline.replace()calls.
Downstream Config
Downstream repositories can optionally create .agconf/config.yaml to customize sync behavior:
- Location:
.agconf/config.yaml(NOT the rootagconf.yamlwhich is for canonical repos) - Schema:
DownstreamConfigSchemaincli/src/config/schema.ts - Loader:
loadDownstreamConfig()incli/src/config/loader.ts
Key distinction:
- Canonical config (
agconf.yaml): Defines content structure, targets, markers - what to sync - Downstream config (
.agconf/config.yaml): User preferences for how sync operates - workflow settings
The workflow key in downstream config controls:
commit_strategy: “pr” (default) or “direct”pr_branch_prefix,pr_title: PR-specific settingscommit_message: Custom commit messagereviewers: Comma-separated GitHub usernames
Rules Sync
Rules are modular, topic-specific instruction files (e.g., security/api-auth.md) synced from a canonical repository. The rules.ts module handles discovery, parsing, and target-specific sync.
Key functions in cli/src/core/rules.ts:
adjustHeadingLevels(content, increment)- Shifts markdown heading levels (respects code blocks, caps at h6)parseRule(content, relativePath)- Parses frontmatter and body using custom YAML parsergenerateRulesSection(rules, markerPrefix)- Concatenates rules into a marked section for CodexsyncRules(sourceDir, targetDir, options)- Main entry point for rules sync
Target-specific behavior:
- Claude: Copies rule files to
.claude/rules/preserving directory structure. Adds metadata frontmatter (agconf_managed,agconf_content_hash,agconf_source_path) for change tracking and orphan detection. - Codex: Concatenates all rules into AGENTS.md under
<!-- {prefix}:rules:start/end -->markers. Heading levels shift +1 to nest under “# Project Rules”. Includes source attribution comments (<!-- Rule: path/to/rule.md -->).
Configuration:
rules_dirin canonicalagconf.yaml(optional) - path to rules directory- Rules tracked in lockfile under
content.ruleswith file list and content hash
Agents Sync
Agents are Claude Code sub-agents (markdown files with YAML frontmatter) synced from a canonical repository. The agents.ts module handles discovery, parsing, and metadata.
Key functions in cli/src/core/agents.ts:
parseAgent(content, relativePath)- Parses frontmatter and bodyvalidateAgentFrontmatter(content, path)- Validates required fields (name, description)addAgentMetadata(agent, prefix)- Adds{prefix}_managedand{prefix}_content_hashmetadata
Target-specific behavior:
- Claude: Copies agent files to
.claude/agents/as flat files. Adds metadata frontmatter for change tracking. - Codex: Not supported. Codex does not have sub-agents. When agents exist in canonical but only Codex target is configured, a warning is displayed and agents are skipped.
Configuration:
agents_dirin canonicalagconf.yaml(optional) - path to agents directory- Agents tracked in lockfile under
content.agentswith file list and content hash
Commit Conventions
Uses Conventional Commits with commitlint enforcement:
<type>(<scope>): <description>
Types: feat, fix, docs, style, refactor, perf, test, chore
CI/CD
- ci.yml: Lint, type check, test on Node 20/22
- release.yml: Semantic-release with automated npm publishing
Release Behavior
fix:commits → patch release (0.0.x)feat:commits → minor release (0.x.0)BREAKING CHANGE:→ blocked (requires manual workflow trigger withallow_major=true)
Major releases are protected to prevent accidental breaking version bumps. See cli/CONTRIBUTING.md for full release docs.
Important Guidelines
CLI Command Changes
When adding or modifying CLI commands, always update the shell completions in cli/src/commands/completion.ts accordingly. The completions provide tab-completion for commands, subcommands, and options.
Testing Requirements
No manual tests. All tests must be runnable programmatically via pnpm test. When implementing new features:
- Write comprehensive unit and integration tests
- Every command file in
cli/src/commands/must have a corresponding test file that covers flag validation, error paths, and orchestration logic - Avoid any verification steps that require manual execution
- Use temp directories and mocks for file system and external dependencies
- For commands that use
process.cwd(), add acwdoption for testability
Check Command Integrity Requirement
Critical: The check command must verify the integrity of ALL synced content.
IMPORTANT: When modifying sync behavior, you MUST also update AND TEST the check command.
When adding new content types to sync or modifying sync behavior:
- Update
sync.tsto sync the new content with proper metadata/hashes - Update
managed-content.tsto add checking functions for the new content type - Update
check.tsto handle the new content type in the check loop - Write tests in
check.test.tsthat verify:- Check passes immediately after sync (hash consistency)
- Check detects unmodified managed files
- Check fails (exit code 1) when managed content is modified
- Non-managed files of the same type are ignored
- Output shows proper file paths and labels
Each synced content type needs:
- A content hash stored during sync (in file metadata or markers)
- Hash verification during check using the same hash function
- Proper type handling in
ManagedFileCheckResultandModifiedFileInfo
Current content types verified by check:
- AGENTS.md global block (
<!-- agconf:global:start/end -->) - AGENTS.md rules section for Codex (
<!-- agconf:rules:start/end -->) - Individual skill files (
.claude/skills/*/SKILL.md) via frontmatter metadata - Individual rule files for Claude (
.claude/rules/**/*.md) via frontmatter metadata - Individual agent files for Claude (
.claude/agents/*.md) via frontmatter metadata
Content Hash Consistency
Critical: All content hashes MUST use the same format: sha256: prefix + 12 hex characters.
Reuse existing hash functions - DO NOT create new ones:
computeContentHash()fromcli/src/core/managed-content.ts- for skill/rule file frontmattercomputeGlobalBlockHash()fromcli/src/core/markers.ts- for AGENTS.md global blockcomputeRulesSectionHash()fromcli/src/core/markers.ts- for AGENTS.md rules section
All these functions return sha256:${hash.slice(0, 12)} format. When adding new content types, import and use these existing functions rather than computing hashes inline. This prevents hash length mismatches (e.g., 12 vs 16 chars) that cause check to fail immediately after sync.
Documentation Synchronization
When removing or renaming CLI commands, subcommands, or options, update ALL documentation references:
AGENTS.md(Commands list and any architecture references)- Root
README.md(command tables and usage examples) cli/README.mdcli/docs/guides that reference the commandcli/src/commands/completion.ts(shell completions)
Export Hygiene
Only export functions, types, and constants that are imported by other modules. If a symbol is only used within its own file, do not export it. Periodically check for unused exports.
Utility Reuse
Before writing a helper function for file I/O, hashing, prefix conversion, or other common patterns, check cli/src/utils/ and existing core modules for an existing implementation. If a utility does not exist yet but the pattern appears in 2+ locations, extract it to cli/src/utils/.
Parallel Worktrees
When working on multiple tasks in parallel, create git worktrees in the .worktrees/ directory inside the workspace (this directory is gitignored). For example:
git worktree add .worktrees/feat-foo -b feat/foo