@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 +27 -10
- package/dist/launcher.cjs +8 -26
- package/package.json +1 -1
- package/schema/agents.schema.json +1 -5
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
|
-
-
|
|
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
|
|
64
|
-
-
|
|
65
|
-
- `installationId` is
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(", ")}).
|
|
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
|
-
|
|
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 = {
|
|
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.
|
|
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
|
-
|
|
5668
|
-
|
|
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
|
+
"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
|
|
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",
|