@ashulab/agent-forge 0.3.0 → 0.4.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/README.md CHANGED
@@ -9,7 +9,7 @@ On each run the launcher:
9
9
  - detects installed provider CLIs on your PATH
10
10
  - asks which provider to use (or takes it from a flag)
11
11
  - starts the provider with the GitHub token and a per-agent git identity injected into the environment
12
- - writes the agent's `systemPrompt` into the provider's startup memory file (`CLAUDE.md` / `AGENTS.md`) so subagents inherit the identity
12
+ - injects the agent's `systemPrompt` per process (`claude --append-system-prompt`, `codex -c developer_instructions`; antigravity falls back to an `AGENTS.md` block)
13
13
 
14
14
  Provider auth stays in the provider CLI — the launcher never handles provider API keys.
15
15
 
@@ -60,9 +60,10 @@ The shape, for reference — the `"$schema"` line points at the published schema
60
60
  }
61
61
  ```
62
62
 
63
- - The **installation id is not stored** — it is resolved on each run, in order: the owner of the repo you launch in, then `account`, then the App's sole installation. So the same agent works across every org the App is installed on, and it survives an uninstall/reinstall (which rotates the id).
64
- - Add `"account": "<org-or-user login>"` only when you run outside a matching repo and the App has more than one installation.
65
- - `installationId` is still accepted as an explicit override — set it to pin a specific id or skip the lookup (offline, or in a git credential helper).
63
+ - The **installation id is not stored** — it is resolved on each run, in order: the owner of the repo you launch in, then the App's sole installation. So the same agent works across every org the App is installed on, and it survives an uninstall/reinstall (which rotates the id).
64
+ - An App installed on more than one account only resolves when you launch from inside a repo it covers that repo picks the installation.
65
+ - `installationId` is accepted as an explicit override — set it to pin a specific id or skip the lookup (offline, or in a git credential helper).
66
+ - One agent, many accounts: a **private** GitHub App only installs on the account that owns it. To run the agent on both a personal account and an org, make the App public or use one App per account — see [docs/github-app.md](docs/github-app.md).
66
67
  - `botId` is optional. When omitted it is resolved from the GitHub API using `botName` so the git author email links commits to the bot. Set it explicitly only to skip that lookup (e.g. offline).
67
68
  - Do not put provider-specific config here — providers are auto-detected from PATH.
68
69
 
@@ -93,17 +94,19 @@ On launch, `agent-forge` prints the scope GitHub actually granted (`scope` row i
93
94
 
94
95
  You need a GitHub App first — its **App ID**, a **private key**, and an **installation**. If you don't have one yet, follow [docs/github-app.md](docs/github-app.md).
95
96
 
97
+ Running `agent-forge` with no agents configured offers to run the wizard for you.
98
+
96
99
  ### Guided (recommended)
97
100
 
98
101
  ```bash
99
102
  agent-forge add
100
103
  ```
101
104
 
102
- You provide the **GitHub App ID** and the **path to its private key**. The wizard derives the rest from the GitHub API — slug (`botName`), bot user id, and the account (asked only when the App is installed on more than one) — asks for a label and an optional system prompt, mints a test token to confirm it works, and writes the entry. It writes to the resolved config path — the global registry (`~/.config/agent-forge/agents.json`) unless `$AGENT_FORGE_CONFIG` or an existing `./agents.json` redirects it.
105
+ You provide the **GitHub App ID** and the **path to its private key**. The wizard derives the rest from the GitHub API — slug (`botName`), bot user id — asks for a label and an optional system prompt, mints a test token to confirm it works, and writes the entry. It writes to the resolved config path — the global registry (`~/.config/agent-forge/agents.json`) unless `$AGENT_FORGE_CONFIG` or an existing `./agents.json` redirects it.
103
106
 
104
107
  ### Manual
105
108
 
106
- Copy one agent object inside the `agents` array and set unique values for `name`, `label`, `appId`, `botName`, `privateKeyPath` — plus `account` if the App has more than one installation. Make sure the private key file exists and is readable.
109
+ Copy one agent object inside the `agents` array and set unique values for `name`, `label`, `appId`, `botName`, `privateKeyPath`. Make sure the private key file exists and is readable.
107
110
 
108
111
  ## Launch
109
112
 
@@ -113,13 +116,26 @@ Interactive:
113
116
  agent-forge
114
117
  ```
115
118
 
116
- Direct flags (passing both skips all prompts; passing one pre-fills it):
119
+ Direct flags (passing both skips the menus; passing one pre-fills it, the other is prompted — or auto-picked when only one agent or provider is available):
117
120
 
118
121
  ```bash
119
122
  agent-forge --agent ops-agent --provider claude
120
123
  agent-forge --agent review-agent --provider codex
121
124
  ```
122
125
 
126
+ Before launching, it prints a summary:
127
+
128
+ ```
129
+ │ provider claude
130
+ │ identity ops-agent[bot]
131
+ │ account AshuLab ← which account the token is for
132
+ │ repo AshuLab/app ← the repo you're in (drives account)
133
+ │ scope write: contents, issues, pull_requests · +4 read
134
+ │ expires ~59m ← installation tokens last ~1h
135
+ ```
136
+
137
+ (The `antigravity` provider adds a `memory` row pointing at the `AGENTS.md` it wrote.)
138
+
123
139
  Other commands:
124
140
 
125
141
  ```bash
@@ -130,10 +146,11 @@ agent-forge --help
130
146
 
131
147
  ### Provider-specific prompt behavior
132
148
 
133
- - `claude`: passed via `--append-system-prompt` (lands in the real system prompt)
134
- - `codex` / `antigravity` (`agy`): no CLI flag — identity comes from `AGENTS.md` only (`agy --prompt` is headless `--print`; a codex positional arg is a fake first user turn)
149
+ `systemPrompt` is injected per process no repo file is touched:
135
150
 
136
- The launcher also writes `systemPrompt` into the provider's startup memory file in the working directory (`CLAUDE.md` for claude, `AGENTS.md` for codex and antigravity), inside a managed `agent-forge:identity` block. This keeps the identity in place for subagents the provider spawns, not just its main thread. The block is rewritten on each run and safe to keep in version control.
151
+ - `claude`: `--append-system-prompt` (lands in the real system prompt)
152
+ - `codex`: `-c developer_instructions=…` (appends a developer message; unlike `model_instructions_file` it does not replace codex's base prompt)
153
+ - `antigravity` (`agy`): no such flag — the launcher writes `systemPrompt` into `AGENTS.md` in the working directory, inside a managed `agent-forge:identity` block. Do not commit it. Run one agent per worktree.
137
154
 
138
155
  ## Token refresh
139
156
 
package/dist/launcher.cjs CHANGED
@@ -5377,19 +5377,9 @@ function pickInstallation(installations, agent) {
5377
5377
  if (installations.length === 0) {
5378
5378
  throw new Error(`GitHub App ${agent.appId} has no installations. Install it on an account or org first.`);
5379
5379
  }
5380
- if (agent.account) {
5381
- const want = String(agent.account).toLowerCase();
5382
- const match = installations.find((item) => item.account.toLowerCase() === want);
5383
- if (!match) {
5384
- throw new Error(
5385
- `GitHub App ${agent.appId} is not installed on "${agent.account}". Installed on: ${installations.map((item) => item.account).join(", ")}.`
5386
- );
5387
- }
5388
- return match.id;
5389
- }
5390
5380
  if (installations.length === 1) return installations[0].id;
5391
5381
  throw new Error(
5392
- `GitHub App ${agent.appId} is installed on ${installations.length} accounts (${installations.map((item) => item.account).join(", ")}). Run inside a repo under one of them, or add "account" to agent "${agent.name}".`
5382
+ `GitHub App ${agent.appId} is installed on ${installations.length} accounts (${installations.map((item) => item.account).join(", ")}). Launch from inside a repo under one of them.`
5393
5383
  );
5394
5384
  }
5395
5385
  function parseGithubRemote(url) {
@@ -5484,7 +5474,9 @@ function getProviderPromptArgs(providerName, agent) {
5484
5474
  if (!prompt) {
5485
5475
  return [];
5486
5476
  }
5487
- return providerName === "claude" ? ["--append-system-prompt", prompt] : [];
5477
+ if (providerName === "claude") return ["--append-system-prompt", prompt];
5478
+ if (providerName === "codex") return ["-c", `developer_instructions=${JSON.stringify(prompt)}`];
5479
+ return [];
5488
5480
  }
5489
5481
 
5490
5482
  // src/identity.js
@@ -5492,7 +5484,7 @@ var import_node_fs3 = require("node:fs");
5492
5484
  var import_node_path3 = require("node:path");
5493
5485
  var START = "<!-- agent-forge:identity:start -->";
5494
5486
  var END = "<!-- agent-forge:identity:end -->";
5495
- var MEMORY_FILE = { claude: "CLAUDE.md", codex: "AGENTS.md", antigravity: "AGENTS.md" };
5487
+ var MEMORY_FILE = { antigravity: "AGENTS.md" };
5496
5488
  function upsertIdentityBlock(content, prompt) {
5497
5489
  const block2 = `${START}
5498
5490
  ${prompt}
@@ -5542,7 +5534,7 @@ var import_node_util3 = require("node:util");
5542
5534
  // package.json
5543
5535
  var package_default = {
5544
5536
  name: "@ashulab/agent-forge",
5545
- version: "0.3.0",
5537
+ version: "0.4.0",
5546
5538
  description: "Give claude/codex/antigravity their own GitHub identity: a bot account, a scoped token minted per run, git attribution to match",
5547
5539
  license: "MIT",
5548
5540
  author: "Diego Ghersi <ghersidl@gmail.com>",
@@ -5664,17 +5656,8 @@ async function addAgentWizard({ embedded = false } = {}) {
5664
5656
  if (meta.installations.length === 0) {
5665
5657
  throw new Error("This App has no installations. Install it on an account or org first.");
5666
5658
  }
5667
- let account;
5668
- if (meta.installations.length === 1) {
5669
- note(`${meta.installations[0].account} \u2014 resolved automatically each run`, "Installation");
5670
- } else {
5671
- account = keep(
5672
- await select({
5673
- message: "Which account is this agent for?",
5674
- options: meta.installations.map((i2) => ({ value: i2.account, label: `${i2.account} (${i2.id})` }))
5675
- })
5676
- );
5677
- }
5659
+ const where = meta.installations.length === 1 ? `${meta.installations[0].account} \u2014 resolved automatically each run` : `${meta.installations.map((i2) => i2.account).join(", ")} \u2014 resolved from the repo you launch in`;
5660
+ note(where, "Installation");
5678
5661
  const name = (keep(await text({ message: "Agent name", placeholder: meta.slug, defaultValue: meta.slug })) || meta.slug).trim();
5679
5662
  const label = (keep(await text({ message: "Label", placeholder: meta.name, defaultValue: meta.name })) || meta.name).trim();
5680
5663
  const systemPrompt = keep(await text({ message: "System prompt (optional)", placeholder: "You are ..." })).trim();
@@ -5684,7 +5667,6 @@ async function addAgentWizard({ embedded = false } = {}) {
5684
5667
  appId,
5685
5668
  botName: meta.slug,
5686
5669
  privateKeyPath,
5687
- ...account ? { account } : {},
5688
5670
  ...systemPrompt ? { systemPrompt } : {}
5689
5671
  };
5690
5672
  const check = spinner();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ashulab/agent-forge",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Give claude/codex/antigravity their own GitHub identity: a bot account, a scoped token minted per run, git attribution to match",
5
5
  "license": "MIT",
6
6
  "author": "Diego Ghersi <ghersidl@gmail.com>",
@@ -25,13 +25,9 @@
25
25
  "type": "string",
26
26
  "description": "GitHub App ID (numeric, stored as a string)"
27
27
  },
28
- "account": {
29
- "type": "string",
30
- "description": "Account/org login where the App is installed. Fallback for installation-id resolution when you run outside a matching repo. Needed only when the App has more than one installation. Resolution order: repo owner, then account, then the sole installation."
31
- },
32
28
  "installationId": {
33
29
  "type": "string",
34
- "description": "Optional override. Normally the installation id is resolved (repo owner, then account, then the sole installation). Set this to pin a specific id or skip the lookup (offline, or in a git credential helper)."
30
+ "description": "Optional override. Normally the installation id is resolved (repo owner, then the App's sole installation). Set this to pin a specific id or skip the lookup (offline, or in a git credential helper)."
35
31
  },
36
32
  "botName": {
37
33
  "type": "string",