awesome-agents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md ADDED
@@ -0,0 +1,60 @@
1
+ # AGENTS.md
2
+
3
+ ## Project Overview
4
+
5
+ `awesome-agents` is a Node.js CLI package for installing reusable operational
6
+ agent profiles into agent harnesses. It intentionally mirrors the command shape
7
+ of `npx skills`, but installs profile artifacts for Codex, Claude Code, and
8
+ OpenCode.
9
+
10
+ The canonical source format is the `touch-grass` layout:
11
+
12
+ - `agents/profiles/*.md`: Markdown profile with YAML frontmatter.
13
+ - `agents/adapters/<harness>/*.md`: optional harness-specific metadata and notes.
14
+
15
+ ## Setup Commands
16
+
17
+ - Install dependencies: `npm install`
18
+ - Run tests: `npm test`
19
+ - Check syntax: `npm run lint`
20
+ - Try the CLI locally: `node ./bin/awesome-agents.js --help`
21
+
22
+ ## Development Workflow
23
+
24
+ - Keep runtime code in `src/` and the executable shim in `bin/`.
25
+ - Use `node --test` for tests under `test/`.
26
+ - Use `--dry-run` in examples that would otherwise write to real user agent
27
+ directories.
28
+ - Do not publish the npm package from this repository unless explicitly asked.
29
+
30
+ ## Testing Instructions
31
+
32
+ - Run the full suite with `npm test`.
33
+ - Add or update tests when changing command behavior, path resolution,
34
+ frontmatter parsing, renderer output, registry writes, or safety checks.
35
+ - Tests should use temporary HOME directories and fixtures, not the user's real
36
+ `~/.codex`, `~/.claude`, or `~/.config/opencode` directories.
37
+
38
+ ## Code Style
39
+
40
+ - Use ESM modules.
41
+ - Prefer Node standard library APIs unless a focused dependency is already in
42
+ `package.json`.
43
+ - Keep generated files marked with `Generated by awesome-agents` so remove and
44
+ overwrite safety checks remain reliable.
45
+ - Keep command output stable enough for humans and use `--json` for scripts.
46
+
47
+ ## Safety
48
+
49
+ - Never overwrite or delete unmanaged harness files by default.
50
+ - Keep install behavior deterministic and noninteractive. `--yes` exists for
51
+ parity with `npx skills`, but the CLI should not require prompts to complete.
52
+ - Do not mutate harness configuration beyond writing the selected generated
53
+ profile files and the `awesome-agents` registry.
54
+
55
+ ## Pull Request Guidelines
56
+
57
+ - Keep changes scoped to one command, renderer, or source-format behavior at a
58
+ time when practical.
59
+ - Run `npm run lint` and `npm test` before handing off changes.
60
+ - Document user-visible CLI behavior in `README.md` when it changes.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pablo Fernandez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # awesome-agents
2
+
3
+ `awesome-agents` is an `npx`-compatible installer for reusable agent profiles.
4
+ It mirrors the useful parts of `npx skills`, but the unit is an operational
5
+ agent profile instead of a skill.
6
+
7
+ The first supported source is `touch-grass`: local at `/Users/customer/touch-grass`
8
+ or remote as `pablof7z/touch-grass`. Profiles are read from
9
+ `agents/profiles/*.md`, adapted for the selected harness, and installed into the
10
+ right place for Codex, Claude Code, or OpenCode.
11
+
12
+ ## Install And Run
13
+
14
+ From this repo:
15
+
16
+ ```bash
17
+ npm install
18
+ npm test
19
+ node ./bin/awesome-agents.js add /Users/customer/touch-grass --agent codex --profile ios-tester --dry-run
20
+ ```
21
+
22
+ Once published, the intended entrypoint is:
23
+
24
+ ```bash
25
+ npx awesome-agents add pablof7z/touch-grass --agent codex --profile ios-tester
26
+ ```
27
+
28
+ ## Commands
29
+
30
+ ```bash
31
+ awesome-agents add [source] [options]
32
+ awesome-agents install [source] [options] # alias for add
33
+ awesome-agents use <source@profile> [options]
34
+ awesome-agents list [options]
35
+ awesome-agents remove <profile...> [options]
36
+ awesome-agents update [profile...] [options]
37
+ awesome-agents init [name]
38
+ ```
39
+
40
+ Useful install options:
41
+
42
+ - `--agent codex|claude-code|opencode|*`
43
+ - `--profile <slug>` or `--profile '*'`
44
+ - `--all` to install all profiles to all supported harnesses
45
+ - `--dry-run` to preview writes
46
+ - `--project` for project-level install, the default
47
+ - `--global` for user-level install
48
+ - `--list` to inspect available source profiles without installing
49
+
50
+ ## Harness Targets
51
+
52
+ Project installs write to:
53
+
54
+ - Codex: `.codex/agents/<profile>.toml`
55
+ - Claude Code: `.claude/agents/<profile>.md`
56
+ - OpenCode: `.opencode/agents/<profile>.md`
57
+
58
+ Global installs write to:
59
+
60
+ - Codex: `$CODEX_HOME/agents/<profile>.toml`, or `~/.codex/agents/<profile>.toml`
61
+ - Claude Code: `$CLAUDE_HOME/agents/<profile>.md`, or `~/.claude/agents/<profile>.md`
62
+ - OpenCode: `$OPENCODE_CONFIG_DIR/agents/<profile>.md`, or `~/.config/opencode/agents/<profile>.md`
63
+
64
+ The CLI keeps its own registry at `.awesome-agents/installed.json` for project
65
+ installs or `~/.awesome-agents/installed.json` for global installs. `list`,
66
+ `remove`, and `update` use this registry and refuse to overwrite or delete files
67
+ that do not contain the generated marker unless `--force` is passed.
68
+
69
+ ## Source Format
70
+
71
+ An agent-profile source should look like:
72
+
73
+ ```text
74
+ agents/
75
+ profiles/
76
+ ios-tester.md
77
+ adapters/
78
+ codex/
79
+ ios-tester.md
80
+ ```
81
+
82
+ Profile files are Markdown with YAML frontmatter. Adapters are optional and can
83
+ provide harness-specific metadata such as model and reasoning effort.
84
+
85
+ ## Examples
86
+
87
+ ```bash
88
+ awesome-agents add /Users/customer/touch-grass --list
89
+ awesome-agents add /Users/customer/touch-grass --agent codex --profile ios-tester
90
+ awesome-agents add /Users/customer/touch-grass --agent codex --profile ios-tester --global
91
+ awesome-agents add pablof7z/touch-grass --all --dry-run
92
+ awesome-agents use pablof7z/touch-grass@ios-ux-ui-critic --agent claude-code
93
+ awesome-agents list --json
94
+ awesome-agents remove ios-tester --agent codex
95
+ awesome-agents update ios-tester --agent codex --dry-run
96
+ ```
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { run } from "../src/cli.js";
4
+
5
+ run(process.argv).catch((error) => {
6
+ const message = error && error.message ? error.message : String(error);
7
+ console.error(`ERROR: ${message}`);
8
+ process.exitCode = 1;
9
+ });
package/docs/cli.md ADDED
@@ -0,0 +1,34 @@
1
+ # CLI Design
2
+
3
+ `awesome-agents` uses `npx skills` as the command-shape reference:
4
+
5
+ - `add` installs a source package.
6
+ - `install` is an alias for `add`.
7
+ - `use` renders a single profile without installing.
8
+ - `list` / `ls` shows installed profiles.
9
+ - `remove` / `rm` removes installed profiles.
10
+ - `update` / `upgrade` reinstalls from the recorded source.
11
+ - `init` creates a profile source skeleton.
12
+
13
+ The CLI is noninteractive for the initial scaffold. Options such as `--yes` are
14
+ accepted for parity, but command behavior should be fully scriptable. Installs
15
+ default to project scope; pass `--global` for user-level installs.
16
+
17
+ ## Source Resolution
18
+
19
+ Supported source values:
20
+
21
+ - Local path: `/Users/customer/touch-grass`, `~/touch-grass`, `.`
22
+ - GitHub shorthand: `pablof7z/touch-grass`
23
+ - GitHub URL: `https://github.com/pablof7z/touch-grass`
24
+
25
+ For GitHub sources, the CLI clones a shallow temporary copy and reads
26
+ `agents/profiles`.
27
+
28
+ ## Install Safety
29
+
30
+ Generated files contain the marker `Generated by awesome-agents`. The CLI refuses
31
+ to overwrite or delete unmarked target files unless `--force` is passed.
32
+
33
+ The registry records only what this CLI installed. It is not intended to discover
34
+ or manage hand-written harness profiles.
@@ -0,0 +1,12 @@
1
+ # Product Notes
2
+
3
+ This folder captures product thinking for `awesome-agents`.
4
+
5
+ Keep these notes grounded in explicit user requests and accepted implementation
6
+ direction. Do not turn incidental implementation choices into product strategy
7
+ unless the user confirms them.
8
+
9
+ ## Files
10
+
11
+ - `awesome-agents-flow-notes.md`: living notes about command shape, source
12
+ format, harness targets, and open questions.
@@ -0,0 +1,45 @@
1
+ # Awesome Agents Flow Notes
2
+
3
+ These are factual notes from the implementation request and current scaffold.
4
+
5
+ ## Core Direction
6
+
7
+ - The package is named `awesome-agents`.
8
+ - It should be installable with `npx`.
9
+ - Its command structure should mirror `npx skills`, but for agent profiles.
10
+ - It should install profiles from `touch-grass`, both local
11
+ `/Users/customer/touch-grass` and GitHub `pablof7z/touch-grass`.
12
+ - Initial harness targets are Codex, Claude Code, and OpenCode.
13
+ - The package should be published after the scaffold works.
14
+
15
+ ## Source Model
16
+
17
+ - Canonical profiles live at `agents/profiles/*.md`.
18
+ - Harness adapters live at `agents/adapters/<harness>/*.md`.
19
+ - Current touch-grass profiles include `ios-tester` and `ios-ux-ui-critic`.
20
+ - The CLI should preserve canonical profile content and generate harness-specific
21
+ install files.
22
+
23
+ ## Command Model
24
+
25
+ - `add` is the primary install command because `npx skills` uses `add`.
26
+ - `install` is an alias because the user explicitly requested an install command.
27
+ - `use` renders one profile without installing it.
28
+ - `list`, `remove`, and `update` operate from an `awesome-agents` registry so
29
+ the CLI manages only its own generated files.
30
+ - `init` creates a starter profile source layout.
31
+ - Install scope defaults to project to match the `npx skills` mental model.
32
+
33
+ ## Safety Constraints
34
+
35
+ - Default behavior should not overwrite or delete unmanaged harness files.
36
+ - `--dry-run` should be available for install, remove, update, and init flows.
37
+ - Tests should exercise fake homes and fixture sources instead of writing to real
38
+ user harness directories.
39
+
40
+ ## Open Questions
41
+
42
+ - Whether future versions should also generate Codex `--profile` config layers in addition to Codex custom agents.
43
+ - Whether touch-grass should add native Claude Code and OpenCode adapters instead
44
+ of relying on generated defaults.
45
+ - Whether future versions should include interactive prompts like `npx skills`.
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "awesome-agents",
3
+ "version": "0.1.0",
4
+ "description": "Install reusable agent profiles into Codex, Claude Code, and OpenCode.",
5
+ "type": "module",
6
+ "bin": {
7
+ "awesome-agents": "bin/awesome-agents.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "docs",
13
+ "README.md",
14
+ "AGENTS.md"
15
+ ],
16
+ "scripts": {
17
+ "lint": "node --check bin/awesome-agents.js && node --check src/*.js && node --check test/*.test.js",
18
+ "test": "node --test"
19
+ },
20
+ "keywords": [
21
+ "agents",
22
+ "agent-profiles",
23
+ "codex",
24
+ "claude-code",
25
+ "opencode",
26
+ "cli"
27
+ ],
28
+ "author": "Pablo Fernandez",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/pablof7z/awesome-agents.git"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "engines": {
38
+ "node": ">=22.12.0"
39
+ },
40
+ "dependencies": {
41
+ "commander": "^15.0.0",
42
+ "yaml": "^2.9.0"
43
+ }
44
+ }
package/src/cli.js ADDED
@@ -0,0 +1,208 @@
1
+ import { Command } from "commander";
2
+ import { PACKAGE_NAME, PACKAGE_VERSION, SUPPORTED_AGENTS } from "./constants.js";
3
+ import {
4
+ initProfile,
5
+ installFromSource,
6
+ listAvailable,
7
+ listInstalled,
8
+ removeInstalled,
9
+ updateInstalled,
10
+ useFromSource
11
+ } from "./installer.js";
12
+
13
+ export async function run(argv = process.argv) {
14
+ const program = new Command();
15
+ program
16
+ .name(PACKAGE_NAME)
17
+ .description("Install reusable agent profiles into Codex, Claude Code, and OpenCode.")
18
+ .version(PACKAGE_VERSION, "-v, --version")
19
+ .helpOption("-h, --help", "Show this help message")
20
+ .showHelpAfterError();
21
+
22
+ addInstallCommand(program, "add");
23
+ addInstallCommand(program, "install");
24
+
25
+ program
26
+ .command("use")
27
+ .argument("[source]", "Source plus profile, for example pablof7z/touch-grass@ios-tester")
28
+ .description("Print one rendered agent profile without installing it")
29
+ .option("-s, --profile <profile>", "Profile slug to use")
30
+ .option("--skill <profile>", "Compatibility alias for --profile")
31
+ .option("-a, --agent <agent>", `Target agent harness (${SUPPORTED_AGENTS.join(", ")})`)
32
+ .option("--json", "Output JSON")
33
+ .option("--home <dir>", "Override HOME for path expansion")
34
+ .action(async (source = undefined, options) => {
35
+ const result = await useFromSource(source, options);
36
+ if (options.json) {
37
+ printJson(result);
38
+ } else {
39
+ process.stdout.write(result.content);
40
+ }
41
+ });
42
+
43
+ program
44
+ .command("list")
45
+ .alias("ls")
46
+ .description("List installed agent profiles")
47
+ .option("-g, --global", "List global installs")
48
+ .option("-p, --project", "List project installs")
49
+ .option("-a, --agent <agents...>", "Filter by agent harness")
50
+ .option("--json", "Output JSON")
51
+ .option("--home <dir>", "Override HOME for path expansion")
52
+ .action(async (options) => {
53
+ const result = await listInstalled(options);
54
+ if (options.json) {
55
+ printJson(result);
56
+ } else {
57
+ printInstalled(result);
58
+ }
59
+ });
60
+
61
+ program
62
+ .command("remove")
63
+ .alias("rm")
64
+ .argument("[profiles...]", "Installed profile slugs to remove")
65
+ .description("Remove installed agent profiles")
66
+ .option("-g, --global", "Remove global installs")
67
+ .option("-p, --project", "Remove project installs")
68
+ .option("-a, --agent <agents...>", "Filter by agent harness")
69
+ .option("-y, --yes", "Accepted for npx skills parity; prompts are not used")
70
+ .option("--all", "Remove all matching installed profiles")
71
+ .option("--dry-run", "Print planned removals without deleting files")
72
+ .option("--force", "Allow removing files without the generated marker")
73
+ .option("--json", "Output JSON")
74
+ .option("--home <dir>", "Override HOME for path expansion")
75
+ .action(async (profiles, options) => {
76
+ const result = await removeInstalled(profiles, options);
77
+ if (options.json) {
78
+ printJson(result);
79
+ } else {
80
+ printOperations(result.operations, result.registryPath);
81
+ }
82
+ });
83
+
84
+ program
85
+ .command("update")
86
+ .alias("upgrade")
87
+ .argument("[profiles...]", "Installed profile slugs to update")
88
+ .description("Update installed agent profiles from their original source")
89
+ .option("-g, --global", "Update global installs")
90
+ .option("-p, --project", "Update project installs")
91
+ .option("-a, --agent <agents...>", "Filter by agent harness")
92
+ .option("-y, --yes", "Accepted for npx skills parity; prompts are not used")
93
+ .option("--dry-run", "Print planned updates without writing files")
94
+ .option("--json", "Output JSON")
95
+ .option("--home <dir>", "Override HOME for path expansion")
96
+ .action(async (profiles, options) => {
97
+ const result = await updateInstalled(profiles, options);
98
+ if (options.json) {
99
+ printJson(result);
100
+ } else {
101
+ printOperations(result.operations, result.registryPath);
102
+ }
103
+ });
104
+
105
+ program
106
+ .command("init")
107
+ .argument("[name]", "New profile slug")
108
+ .description("Initialize a profile source layout in the current directory")
109
+ .option("--dry-run", "Print planned files without writing")
110
+ .option("--force", "Overwrite existing initialized files")
111
+ .option("--json", "Output JSON")
112
+ .action(async (name, options) => {
113
+ const result = await initProfile(name, { ...options, cwd: process.cwd() });
114
+ if (options.json) {
115
+ printJson(result);
116
+ } else {
117
+ console.log(`${result.action}:`);
118
+ for (const file of result.files) {
119
+ console.log(` ${file}`);
120
+ }
121
+ }
122
+ });
123
+
124
+ if (argv.length <= 2) {
125
+ program.help();
126
+ return;
127
+ }
128
+
129
+ await program.parseAsync(argv);
130
+ }
131
+
132
+ function addInstallCommand(program, commandName) {
133
+ program
134
+ .command(commandName)
135
+ .argument("[source]", "Local path, GitHub owner/repo, or GitHub URL")
136
+ .description(commandName === "install" ? "Alias for add" : "Install agent profiles from a source")
137
+ .option("-g, --global", "Install globally")
138
+ .option("-p, --project", "Install into the current project (default)")
139
+ .option("-a, --agent <agents...>", `Target agent harnesses (${SUPPORTED_AGENTS.join(", ")}, or *)`)
140
+ .option("-s, --profile <profiles...>", "Profile slugs to install (or *)")
141
+ .option("--skill <profiles...>", "Compatibility alias for --profile")
142
+ .option("-l, --list", "List available profiles in the source without installing")
143
+ .option("-y, --yes", "Accepted for npx skills parity; prompts are not used")
144
+ .option("--all", "Install all profiles to all supported agents")
145
+ .option("--dry-run", "Print planned installs without writing files")
146
+ .option("--force", "Allow overwriting files without the generated marker")
147
+ .option("--json", "Output JSON")
148
+ .option("--home <dir>", "Override HOME for path expansion")
149
+ .action(async (source = undefined, options) => {
150
+ if (options.list) {
151
+ const profiles = await listAvailable(source, options);
152
+ if (options.json) {
153
+ printJson({ profiles });
154
+ } else {
155
+ printAvailable(profiles);
156
+ }
157
+ return;
158
+ }
159
+
160
+ const result = await installFromSource(source, options);
161
+ if (options.json) {
162
+ printJson(result);
163
+ } else {
164
+ printOperations(result.operations, result.registryPath);
165
+ }
166
+ });
167
+ }
168
+
169
+ function printAvailable(profiles) {
170
+ if (profiles.length === 0) {
171
+ console.log("No profiles found.");
172
+ return;
173
+ }
174
+ for (const profile of profiles) {
175
+ console.log(`${profile.slug} ${profile.summary || profile.name}`);
176
+ }
177
+ }
178
+
179
+ function printInstalled(result) {
180
+ if (result.installs.length === 0) {
181
+ console.log(`No ${result.scope} profiles installed.`);
182
+ return;
183
+ }
184
+
185
+ for (const install of result.installs) {
186
+ const missing = install.exists ? "" : " (missing target)";
187
+ console.log(`${install.profile} ${install.harness} ${install.target}${missing}`);
188
+ }
189
+ console.log(`Registry: ${result.registryPath}`);
190
+ }
191
+
192
+ function printOperations(operations, registryPath) {
193
+ if (operations.length === 0) {
194
+ console.log("No matching profiles.");
195
+ return;
196
+ }
197
+
198
+ for (const operation of operations) {
199
+ console.log(`${operation.action}: ${operation.profile} -> ${operation.harness} at ${operation.target}`);
200
+ }
201
+ if (registryPath) {
202
+ console.log(`Registry: ${registryPath}`);
203
+ }
204
+ }
205
+
206
+ function printJson(value) {
207
+ console.log(JSON.stringify(value, null, 2));
208
+ }
@@ -0,0 +1,19 @@
1
+ export const PACKAGE_NAME = "awesome-agents";
2
+ export const PACKAGE_VERSION = "0.1.0";
3
+ export const DEFAULT_SOURCE = "pablof7z/touch-grass";
4
+ export const DEFAULT_AGENT = "codex";
5
+ export const SUPPORTED_AGENTS = ["codex", "claude-code", "opencode"];
6
+ export const REGISTRY_DIRNAME = ".awesome-agents";
7
+ export const REGISTRY_FILENAME = "installed.json";
8
+ export const GENERATED_MARKER = "Generated by awesome-agents";
9
+
10
+ export const AGENT_ALIASES = new Map([
11
+ ["codex", "codex"],
12
+ ["openai", "codex"],
13
+ ["openai-codex", "codex"],
14
+ ["claude", "claude-code"],
15
+ ["claude-code", "claude-code"],
16
+ ["claudecode", "claude-code"],
17
+ ["opencode", "opencode"],
18
+ ["open-code", "opencode"]
19
+ ]);
@@ -0,0 +1,33 @@
1
+ import YAML from "yaml";
2
+
3
+ export function parseFrontmatter(text, filePath = "document") {
4
+ if (!text.startsWith("---")) {
5
+ return { attributes: {}, body: text };
6
+ }
7
+
8
+ const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?/);
9
+ if (!match) {
10
+ throw new Error(`Invalid YAML frontmatter in ${filePath}`);
11
+ }
12
+
13
+ let attributes;
14
+ try {
15
+ attributes = YAML.parse(match[1]) ?? {};
16
+ } catch (error) {
17
+ throw new Error(`Could not parse YAML frontmatter in ${filePath}: ${error.message}`);
18
+ }
19
+
20
+ return {
21
+ attributes,
22
+ body: text.slice(match[0].length).trimStart()
23
+ };
24
+ }
25
+
26
+ export function stringifyFrontmatter(attributes, body) {
27
+ const yaml = YAML.stringify(attributes, {
28
+ collectionStyle: "block",
29
+ lineWidth: 0
30
+ }).trimEnd();
31
+
32
+ return `---\n${yaml}\n---\n\n${body.trimStart()}`;
33
+ }