diff --git a/README.md b/README.md index ce5cdc1..34e0aee 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,105 @@ # Agentfiles -A CLI tool that keeps your AI coding assistant configuration in one place and copies the right pieces into each of your projects. +Agentfiles is a CLI tool that enables you to centrally manage your AI coding assistant configurations across multiple projects. By setting up a personal profile, yor agent configurations are propagated from a single source, minimzing agent management overhead and drift over time. -If you've never touched this tool before, read on. This README assumes you know -nothing about it. +- If you are new to Agentfiles, please read on to learn the basics. +- Go to [Prerequisites and installation](#prerequisites-and-installation) for first-time setup. +- Go to [Quickstart](#quickstart-your-first-end-to-end-run) for hands-on usage instructions. --- -## Why does this exist? +## What is Agentfiles? -Modern AI coding assistants like Claude Code, Codex, Cursor, opencode each want -their own configuration files scattered across every repository you work on: +Modern AI coding assistants like Claude Code, Codex, Cursor or opencode all require individual configuration files added to each repository you work on: - Claude Code reads files under `.claude/` and `.mcp.json`. - Codex reads `AGENTS.md`, `.codex/config.toml`, and `.codex/skills/`. - Cursor reads `.cursor/commands/` and `.cursor/config.json`. - opencode reads `.opencode/`. -If you work on many repos, you end up copy-pasting the same skills, settings, hooks, and prompts into every one of them. When you improve a skill in one place, the others drift out of sync. Deleting something cleanly is risky because you can't remember what was hand-written vs. what you copied in. +Across multiple repos, skill, setting, hook, and prompt assets get duplicated and eventually drift out of sync. Updates and deletions become complicated because copy-pasted or derivative assets are hard to distinguish from hand-written ones. -`agentfiles` solves this by treating your **profile folder** as the single -source of truth, and treating the files inside each project repository as -**generated outputs** that it plans, previews, and writes for you. +`agentfiles` solves this by making your personal **profile folder** the single source of truth, as well as planning, previewing, and writing **base assets** that you can selectively propagate to each of your project repositories. -You edit your skills, prompts, and settings once, in the profile. Then you -`apply` them into as many project repos as you like. +You edit your skills, prompts, and settings (**base assets**) once, in the profile folder. Then you +`apply` them to as many project repos as you like, resulting in **propagated assets** placed in those projects. --- -## The big idea in one picture +## Workflow overview ``` -┌─────────────────────────────────────────┐ -│ ~/.agentprofiles.json (registry) │ Global index. Lists your profiles. -└─────────────────────────────────────────┘ +┌─────────────────────────────────────────────────┐ +│ ~/.config/.agentfiles/.profiles.json (registry) │ Global index. Lists your profiles. +│ ~/.config/.agentfiles/.projects.json (registry) │ Global index. Lists your projects. +└─────────────────────────────────────────────────┘ │ │ points to ▼ -┌─────────────────────────────────────────┐ -│ ~/profiles/personal/ (one profile) │ The source of truth. -│ ├── profile.json │ You edit content here. -│ ├── assets/ │ -│ │ ├── skill/review/SKILL.md │ -│ │ ├── settings/… │ -│ │ └── … │ -│ └── projects/ │ -│ ├── app.json (project spec) │ -│ └── website.json │ -└─────────────────────────────────────────┘ +┌─────────────────────────────────────────────────┐ +│ ~/profiles/personal/ (one profile) │ The source of truth. +│ ├── profile.json │ You edit your base assets here. +│ ├── assets/ │ +│ │ ├── skill/review/SKILL.md │ +│ │ ├── settings/… │ +│ │ └── … │ +│ └── projects/ │ +│ ├── app.json (project spec) │ +│ └── website.json │ +└─────────────────────────────────────────────────┘ │ │ render + apply ▼ -┌─────────────────────────────────────────┐ -│ ~/src/app/ (a target repository) │ Generated outputs land here. -│ ├── AGENTS.md │ -│ ├── .claude/skills/review/SKILL.md │ -│ ├── .codex/skills/review/SKILL.md │ -│ ├── .cursor/commands/review.md │ -│ └── .agentfiles/state.json │ Bookkeeping for drift detection. -└─────────────────────────────────────────┘ +┌─────────────────────────────────────────────────┐ +│ ~/src/app/ (a target repository) │ Propagated assets land here. +│ ├── AGENTS.md │ +│ ├── .claude/skills/review/SKILL.md │ +│ ├── .codex/skills/review/SKILL.md │ +│ ├── .cursor/commands/review.md │ +│ └── .agentfiles/state.json │ Bookkeeping for drift detection. +└─────────────────────────────────────────────────┘ ``` -One profile can feed many target projects. Each project chooses which **assets** (skills, settings, prompts, etc.) it wants and which **agents** (Claude Code, Codex, Cursor, opencode) it wants to render for. +One profile can feed any number of target projects. Each project can declare which **assets** (skills, settings, prompts, etc.) it needs and for which **agents** (Claude Code, Codex, Cursor, opencode) it wants to render them. --- ## Key terms -Before you run any commands, it helps to know the vocabulary. These words mean -something specific in `agentfiles` and are used throughout the TUI and docs. +Before you run any commands, it helps to know the vocabulary. These words mean something specific in `agentfiles` and are used throughout the TUI and docs. | Term | What it is | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Registry** | A single file at `~/.agentprofiles.json` that lists every profile you have. Used purely for discovery. | +| **Registry** | A single file at `~/.config/.agentfiles/profiles.json` that lists every profile you have. Used purely for discovery. | | **Profile** | A folder containing your reusable content. Holds `profile.json`, an `assets/` tree, and a `projects/` tree. This is the **source of truth**. | | **Asset** | One reusable unit of content — a skill, a settings file, a hook, etc. Lives inside a profile and has its own `asset.json` manifest. | | **Project** | A target repository together with a list of enabled agents and selected assets. Defined by a JSON file inside the profile's `projects/` folder. | | **Enabled agent** | An AI tool the project renders for. One of: `codex`, `claude-code`, `cursor`, `opencode`. | | **Render plan** | The set of files `agentfiles` wants to write into a project, computed from its selected assets. | | **Preview** | A render plan compared against what's already in the project repo. Shows creates, updates, drift, and delete candidates. | -| **Managed surfaces** | The only paths `agentfiles` is allowed to touch inside a repo: `AGENTS.md`, `.claude/`, `.cursor/`, `.codex/`, `.opencode/`, `.mcp.json`. Anything outside this list is left alone. | +| **Managed paths** | The only paths `agentfiles` is allowed to access inside a repo: `AGENTS.md`, `.claude/`, `.cursor/`, `.codex/`, `.opencode/`, `.mcp.json`. Anything outside this list is not read or written. | | **Managed state** | A bookkeeping file at `/.agentfiles/state.json` listing which files were written last time and what their hashes were. Used to detect drift. | -| **Drift** | A managed file was edited locally after the last apply, so its hash no longer matches what `agentfiles` wrote. Shown in previews so you don't lose that edit by accident. | -| **Delete candidate** | A file inside a managed surface that `agentfiles` recognizes but no longer wants. Never deleted automatically — `Project → Apply` asks you to confirm removal when candidates exist. | +| **Drift** | A managed asset file that was edited locally after the last `apply` command, so its hash no longer matches what `agentfiles` wrote. Shown in previews so you don't lose that edit by accident. | +| **Delete candidate** | A file inside a managed surface that `agentfiles` recognizes but no longer wants. Never deleted automatically — `Project → Apply` asks you to confirm removal when candidates exist. See [Safe deletion](#safe-deletion) for details of this workflow.| -A longer glossary lives in [`docs/glossary.md`](./docs/glossary.md). +A full glossary lives in [`docs/glossary.md`](./docs/glossary.md). --- -## Requirements +## Prerequisites and installation + +### Requirements - **Go 1.26+** to build from source. - A POSIX shell (Linux or macOS). The project builds for both. - Optional: [`mise`](https://mise.jdx.dev/) to pin the Go toolchain (see `mise.toml`). -There is no database, no daemon, and no network service. Everything is plain -JSON files on your disk. +There is no database, no daemon, and no network service. Everything is plain JSON files on your disk. --- -## Install / build +### Install / build Clone the repo and build with `make`: @@ -110,9 +109,7 @@ cd agentfiles make build ``` -This produces a binary at `./bin/af`. Put it on your `PATH` (or alias it to -`agentfiles` — that's the name the CLI uses internally and throughout this -README). +This produces a binary at `./bin/af`. Put it on your `PATH` (or alias it to `agentfiles` — that's the name the CLI uses internally and throughout this README). ```bash # Example: put a symlink where your shell will find it @@ -132,41 +129,42 @@ Other common `make` targets: --- -## Quickstart: your first end-to-end run +## Run Agentfiles -`agentfiles` is fully TUI-driven. Run the `af` command and the top-level menu opens. From there you pick a category, then an action, and the matching form walks you through it. +`agentfiles` is fully TUI-driven. Run the `af` command and the top-level menu opens. From there you pick a category, then an action, and the matching form walks you through it: -There are no per-command flags to memorize and no subcommand paths: every input is collected through the TUI. +[![demo](docs/demo.gif)](https://asciinema.org/a/61nrRvxqxMsCogpL) -Press `Esc` at any prompt to back out one level. `Ctrl+C` works the same -way. +Press `Esc` at any prompt to back out one level. `Ctrl+C` does the same. ### 1. Create a profile > [!NOTE] -> You can create a git repository inside the profile folder. This way you can share a profile with other people working on the same project. If you already have a profile that you want to register (for example if you cloned someone else's profile) you can use `register` to add it +> You can create a git repository inside the profile folder. This way you can share a profile with other people working on the same project. You can also register an existing profile (for example if you cloned someone else's profile) by using `register` to add it to your `agentfiles` instance. -Pick `Profile → Create`. The form prompts for a display name and a path. After it completes, `~/{your-path}/{your-profile}/` exists with `profile.json` and empty `assets/` and `projects/` subfolders, and the profile is registered in `~/.agentprofiles.json`. +Pick `Profile → Create`. The form prompts for a display name and a path. After it completes, `~/{your-path}/{your-profile}/` exists with `profile.json` and empty `assets/` and `projects/` subfolders, and the profile is registered in `~/.config/.agentfiles/profiles.json`. ### 2. Add a reusable skill -A **skill** is one of the asset types. It's a markdown file (`SKILL.md`) plus -optional supporting files that can be rendered for every agent. +A **skill** is one of the asset types. It is a markdown file (`SKILL.md`) plus optional supporting files that can be rendered for every agent. + +(EDITORIAL NOTE: Instead of asking the first-time user to write their own SKILL.md, we could create an example project that the user can register to get to know some skill alternatives, profile layout, etc. Maybe as an optional on-boarding path. -> checkout example) -Pick `Asset → Init`. The form picks the owning profile from a list, presents the supported asset types as a Select, and asks for the id, name, and description. -The new directory (e.g. `~/profiles/personal/assets/skill/review/`) is printed when the form -completes; open `SKILL.md` and write your actual content. +From the main menu, select `Profiles → Edit → Create Asset`. The Create Asset form asks for the id, name, and description of the new asset, and presents the supported asset types. The new asset directory (e.g. `~/profiles/personal/assets/skill/review/`) is printed when the form completes. You can now open `SKILL.md` in this directory and write your actual content. ### 3. Register a target project -Pick `Project → Add`. Tell `agentfiles` which repository this profile should feed, which AI agents it should render for, and which assets to include. The form picks the profile, asks for a name and absolute path, lets you multi-select the supported agents, and lets you multi-select assets from the -ones already defined in the chosen profile. -The project manifest lands in the profile's `projects/` folder; nothing is written into the target -repository yet. +From the main menu, select `Profiles → Edit → Create Project`. Tell `agentfiles` which repository your profile should propagate with assets and which AI agents it should render for. + +The project manifest lands in the profile's `projects/` folder; nothing is written into the target repository yet. + +### 4. Select assets to propagate + +Once your project is created, it appears under `Profiles → Projects`. Select `Select Assets`. The form allows you to define which assets you want to propagate to the selected project. It should list the skill added in step 3. Select it. It shows up in the `Selected Assets` list. -### 4. Preview what will happen +### 5. Preview changes -Always run `Plan` before `Apply`. It's read-only and shows you exactly what files would be created, updated, or flagged. +Always run `Plan` before `Apply`. It is read-only and shows you exactly what files would be created, updated, or flagged. Pick `Project → Plan`. The form picks the profile, then the project, then prints the preview: @@ -176,21 +174,21 @@ Project: /home/you/src/app - [create] .codex/skills/review/SKILL.md: file missing ``` -### 5. Apply the changes +### 6. Apply the changes -Pick `Project → Apply`. The flow runs `Plan`, shows the same summary, and then asks you to confirm before writing. If delete candidates exist, the form also asks whether to remove them. +Pick `Project → Apply`. The flow runs `Plan`, shows the same summary, and then asks you to confirm before writing. If the project contains assets removed from active management (delete candidates), the form also asks whether to remove them. After apply succeeds, `~/src/app/.agentfiles/state.json` records what was written. Next time you run `Plan`, `agentfiles` will compare against that state. ### 6. Iterate -Edit the skill in your profile (`~/profiles/personal/assets/skill/review/SKILL.md`), run `af` again and pick `Project → Apply`, and the changes propagate. The profile is the source of truth; the project's `.claude/` and `.codex/` are outputs. +Edit the skill in your profile (`~/profiles/personal/assets/skill/review/SKILL.md`), run `af` again and pick `Project → Apply`, and the changes propagate. The profile is the source of truth; the project's `.claude/` and `.codex/` are propagated assets. --- ## Menu reference -`af` takes no positional arguments. Running it opens the main menu; everything else is a submenu pick followed by a form. The only flag the binary accepts is `--registry `, which overrides the default `~/.agentprofiles.json` location (useful for tests or isolated environments). +`af` takes no positional arguments. Running it opens the main menu; everything else is a submenu pick followed by a form. The only flag the binary accepts is `--registry `, which overrides the default `~/.config/.agentfiles/profiles.json` location (useful for tests or isolated environments). ### Profile @@ -258,8 +256,7 @@ Each `asset.json` can narrow which agents are allowed to use it: ### Generic projections -For `mcp`, `rule`, `hook`, and any custom-shaped asset, you describe the -source-to-target mapping yourself in the manifest: +For `mcp`, `rule`, `hook`, and any custom-shaped asset, you must describe the source-to-target mapping yourself in the manifest: ```json { @@ -278,8 +275,7 @@ source-to-target mapping yourself in the manifest: } ``` -Targets **must** fall inside a managed surface (see next section). Anything -outside is refused at render time. +Targets **must** be located inside a managed surface (see next section). Anything outside is refused at render time. --- @@ -304,18 +300,15 @@ Each apply writes hashes of every managed file into `/.agentfiles/state.js - **File unchanged** → skipped. - **File changed by `agentfiles`** (i.e. the profile has new content) → reported as `update`. -- **File changed locally** (hash differs from state, state exists) → reported - as `drift`. You're being warned that a hand-edit will be overwritten if you - apply. +- **File changed locally** (hash differs from state, state exists) → reported as `drift`. You will be warned that your edits will be overwritten if you run `apply`. ### Safe deletion -If a file used to be managed but is no longer part of the render plan - say you removed an asset from the project's selection - it shows up as a **delete candidate**. -`Project → Apply` does _not_ remove these automatically. When candidates exist, the flow pops an extra confirm prompt ("Delete recognized unmanaged files?") before the final apply confirmation; answer yes to remove them, or clean them up by hand. +If a file was previously managed but is no longer part of the render plan (for example you removed an asset from the project's selection) it shows up as a **delete candidate**. `Project → Apply` does _not_ remove these automatically. When unmanaged files exist in your project, the flow pops an extra confirm prompt ("Delete recognized unmanaged files?") before the final apply confirmation; answer yes to remove them, or clean them up by hand. --- -## File layout on disk +## File layout on disk (TODO: review against current version) ### Profile folder @@ -336,9 +329,9 @@ If a file used to be managed but is no longer part of the render plan - say you └── app.json # One project manifest per target repo. ``` -### Target repository (after apply) +### Target repository (after running `apply`) -Only managed surfaces are touched: +Only managed surfaces are modified: ``` ~/app-dir/ @@ -359,29 +352,25 @@ Only managed surfaces are touched: └── state.json # Managed-state bookkeeping. ``` -### Global registry +### Global registry (TODO: review against current version) ``` -~/.agentprofiles.json +~/.config/.agentfiles/profiles.json ``` -A single JSON file listing every registered profile with its id, name, path, -creation time, and last-opened time. It stores **only pointers** — no asset -content lives here. +A single JSON file listing every registered profile with its id, name, path, creation time, and last-opened time. It stores **only pointers** — no assets live here. --- ## Ownership rule -One target project path belongs to at most one profile. If profile A already -owns `~/src/app`, profile B cannot `project add` the same path. This prevents -two profiles from silently fighting over the same generated files. +One target project path belongs to at most one profile. If profile A already owns `~/src/app`, profile B cannot `project add` the same path. This prevents two profiles from silently conflicting over the same generated files. --- -## Current status +## Current features -This is an initial implementation. Working today: +This is an initial implementation. Current feature set: - Profile creation, registration, and listing - Asset scaffolding for all six types @@ -396,25 +385,17 @@ This is an initial implementation. Working today: ## License -Agentfiles is licensed under the **GNU Affero General Public License v3.0** -(AGPL-3.0). See [`LICENSE`](./LICENSE) for the full text. +Agentfiles is licensed under the **GNU Affero General Public License v3.0** (AGPL-3.0). See [`LICENSE`](./LICENSE) for the full text. -In short: you may use, modify, and distribute this software freely, but if you -run a modified version as a network service you must make your source available -to its users (AGPL §13). +In short: you may use, modify, and distribute this software freely, but if you run a modified version as a network service you must make your source available to its users (AGPL §13). ### Commercial license -A separate commercial license — permitting use without the AGPL's copyleft and -network-source obligations — is available for organizations that cannot comply -with the AGPL. Contact **info@hexworks.org**. +A separate commercial license — permitting use without the AGPL's copyleft and network-source obligations — is available for organizations that cannot comply with the AGPL. Contact **info@hexworks.org**. ### Contributing -By submitting a contribution you agree to the -[Contributor License Agreement](./CLA.md), under which you assign copyright in -your contribution to Hexworks. This lets Hexworks offer the project under both -the AGPL and a commercial license. See [`CLA.md`](./CLA.md) for details. +By submitting a contribution you agree to the [Contributor License Agreement](./CLA.md), under which you assign copyright in your contribution to Hexworks. This lets Hexworks offer the project under both the AGPL and a commercial license. See [`CLA.md`](./CLA.md) for details. --- diff --git a/docs/demo.gif b/docs/demo.gif new file mode 100644 index 0000000..a955ab6 Binary files /dev/null and b/docs/demo.gif differ