thepopebot 1.2.74-beta.39 → 1.2.74-beta.40
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/bin/CLAUDE.md +0 -2
- package/bin/cli.js +1 -59
- package/lib/chat/components/containers-page.js +6 -9
- package/lib/chat/components/containers-page.jsx +7 -8
- package/lib/tools/docker.js +14 -2
- package/package.json +1 -1
- package/templates/docs/CLI.md +2 -8
- package/templates/docs/CONFIGURATION.md +4 -15
- package/templates/docs/SECURITY.md +3 -16
- package/templates/docs/SKILLS.md +2 -18
- package/templates/skills/CLAUDE.md.template +1 -12
- package/templates/skills/README.md +0 -2
- package/templates/skills/{llm-secrets → get-secret}/SKILL.md +2 -2
- package/templates/skills/{llm-secrets/llm-secrets.js → get-secret/get-secret.js} +7 -7
- package/templates/skills/modify-self/SKILL.md +0 -12
package/bin/CLAUDE.md
CHANGED
|
@@ -13,8 +13,6 @@ Entry point: `cli.js` (invoked via `npx thepopebot <command>`).
|
|
|
13
13
|
| `reset [file]` | Restore a template file to defaults |
|
|
14
14
|
| `diff [file]` | Show diff between user file and package template |
|
|
15
15
|
| `reset-auth` | Regenerate `AUTH_SECRET` (invalidates all sessions) |
|
|
16
|
-
| `set-agent-secret <KEY> [VALUE]` | Set GitHub secret with `AGENT_` prefix + update `.env` |
|
|
17
|
-
| `set-agent-llm-secret <KEY> [VALUE]` | Set GitHub secret with `AGENT_LLM_` prefix |
|
|
18
16
|
| `set-var <KEY> [VALUE]` | Set GitHub repository variable |
|
|
19
17
|
| `user:password <email>` | Change user password |
|
|
20
18
|
| `sync <path>` | Dev helper — sync local package to test install |
|
package/bin/cli.js
CHANGED
|
@@ -57,8 +57,6 @@ Commands:
|
|
|
57
57
|
reset [file] Restore a template file (or list available templates)
|
|
58
58
|
diff [file] Show differences between project files and package templates
|
|
59
59
|
sync <path> Sync local package to a test install (build, pack, Docker)
|
|
60
|
-
set-agent-secret <KEY> [VALUE] Set a GitHub secret with AGENT_ prefix (also updates .env)
|
|
61
|
-
set-agent-llm-secret <KEY> [VALUE] Set a GitHub secret with AGENT_LLM_ prefix
|
|
62
60
|
set-var <KEY> [VALUE] Set a GitHub repository variable
|
|
63
61
|
user:password <email> Change a user's password
|
|
64
62
|
`);
|
|
@@ -264,7 +262,7 @@ async function init() {
|
|
|
264
262
|
}
|
|
265
263
|
|
|
266
264
|
// Create default skill activation symlinks
|
|
267
|
-
const defaultSkills = ['
|
|
265
|
+
const defaultSkills = ['get-secret'];
|
|
268
266
|
const activeDir = path.join(cwd, 'skills', 'active');
|
|
269
267
|
fs.mkdirSync(activeDir, { recursive: true });
|
|
270
268
|
for (const skill of defaultSkills) {
|
|
@@ -711,56 +709,6 @@ async function promptForValue(key) {
|
|
|
711
709
|
return value;
|
|
712
710
|
}
|
|
713
711
|
|
|
714
|
-
async function setAgentSecret(key, value) {
|
|
715
|
-
if (!key) {
|
|
716
|
-
console.error('\n Usage: thepopebot set-agent-secret <KEY> [VALUE]\n');
|
|
717
|
-
console.error(' Example: thepopebot set-agent-secret ANTHROPIC_API_KEY\n');
|
|
718
|
-
process.exit(1);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
if (!value) value = await promptForValue(key);
|
|
722
|
-
|
|
723
|
-
const { owner, repo } = loadRepoInfo();
|
|
724
|
-
const prefixedName = `AGENT_${key}`;
|
|
725
|
-
|
|
726
|
-
const { setSecret } = await import(path.join(__dirname, '..', 'setup', 'lib', 'github.mjs'));
|
|
727
|
-
const { updateEnvVariable } = await import(path.join(__dirname, '..', 'setup', 'lib', 'auth.mjs'));
|
|
728
|
-
|
|
729
|
-
const result = await setSecret(owner, repo, prefixedName, value);
|
|
730
|
-
if (result.success) {
|
|
731
|
-
console.log(`\n Set GitHub secret: ${prefixedName}`);
|
|
732
|
-
updateEnvVariable(key, value);
|
|
733
|
-
console.log(` Updated .env: ${key}`);
|
|
734
|
-
console.log('');
|
|
735
|
-
} else {
|
|
736
|
-
console.error(`\n Failed to set ${prefixedName}: ${result.error}\n`);
|
|
737
|
-
process.exit(1);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
async function setAgentLlmSecret(key, value) {
|
|
742
|
-
if (!key) {
|
|
743
|
-
console.error('\n Usage: thepopebot set-agent-llm-secret <KEY> [VALUE]\n');
|
|
744
|
-
console.error(' Example: thepopebot set-agent-llm-secret BRAVE_API_KEY\n');
|
|
745
|
-
process.exit(1);
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
if (!value) value = await promptForValue(key);
|
|
749
|
-
|
|
750
|
-
const { owner, repo } = loadRepoInfo();
|
|
751
|
-
const prefixedName = `AGENT_LLM_${key}`;
|
|
752
|
-
|
|
753
|
-
const { setSecret } = await import(path.join(__dirname, '..', 'setup', 'lib', 'github.mjs'));
|
|
754
|
-
|
|
755
|
-
const result = await setSecret(owner, repo, prefixedName, value);
|
|
756
|
-
if (result.success) {
|
|
757
|
-
console.log(`\n Set GitHub secret: ${prefixedName}\n`);
|
|
758
|
-
} else {
|
|
759
|
-
console.error(`\n Failed to set ${prefixedName}: ${result.error}\n`);
|
|
760
|
-
process.exit(1);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
712
|
async function setVar(key, value) {
|
|
765
713
|
if (!key) {
|
|
766
714
|
console.error('\n Usage: thepopebot set-var <KEY> [VALUE]\n');
|
|
@@ -843,12 +791,6 @@ switch (command) {
|
|
|
843
791
|
await sync(args[0]);
|
|
844
792
|
break;
|
|
845
793
|
}
|
|
846
|
-
case 'set-agent-secret':
|
|
847
|
-
await setAgentSecret(args[0], args[1]);
|
|
848
|
-
break;
|
|
849
|
-
case 'set-agent-llm-secret':
|
|
850
|
-
await setAgentLlmSecret(args[0], args[1]);
|
|
851
|
-
break;
|
|
852
794
|
case 'set-var':
|
|
853
795
|
await setVar(args[0], args[1]);
|
|
854
796
|
break;
|
|
@@ -93,18 +93,15 @@ function ContainerRow({ container, onRequestStop, isStopping, isStarting }) {
|
|
|
93
93
|
const isStopped = container.state === "exited" || container.state === "dead" || container.state === "created";
|
|
94
94
|
const imageName = container.image.includes("/") ? container.image.split("/").pop() : container.image;
|
|
95
95
|
return /* @__PURE__ */ jsxs("tr", { className: "border-t border-border", children: [
|
|
96
|
-
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3", children: /* @__PURE__ */ jsx(StateBadge, { state: container.state }) }),
|
|
97
|
-
/* @__PURE__ */
|
|
98
|
-
|
|
99
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground truncate", children: imageName })
|
|
100
|
-
] }),
|
|
101
|
-
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 text-xs text-right hidden md:table-cell", children: isRunning && container.stats ? /* @__PURE__ */ jsxs("span", { children: [
|
|
96
|
+
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 whitespace-nowrap", children: /* @__PURE__ */ jsx(StateBadge, { state: container.state }) }),
|
|
97
|
+
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 min-w-0 whitespace-nowrap", children: /* @__PURE__ */ jsx("div", { className: "text-sm font-medium truncate", title: imageName, children: container.name }) }),
|
|
98
|
+
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 text-xs text-right hidden md:table-cell whitespace-nowrap", children: isRunning && container.stats ? /* @__PURE__ */ jsxs("span", { children: [
|
|
102
99
|
container.stats.cpu.toFixed(1),
|
|
103
100
|
"%"
|
|
104
101
|
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
105
|
-
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 text-xs text-right hidden md:table-cell", children: isRunning && container.stats ? /* @__PURE__ */ jsx("span", { children: formatBytes(container.stats.memUsage) }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
106
|
-
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 text-xs text-muted-foreground hidden lg:table-cell", children: container.status }),
|
|
107
|
-
/* @__PURE__ */ jsx("td", { className: "py-2.5 text-right", children: /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1.5", children: [
|
|
102
|
+
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 text-xs text-right hidden md:table-cell whitespace-nowrap", children: isRunning && container.stats ? /* @__PURE__ */ jsx("span", { children: formatBytes(container.stats.memUsage) }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
103
|
+
/* @__PURE__ */ jsx("td", { className: "py-2.5 pr-3 text-xs text-muted-foreground hidden lg:table-cell whitespace-nowrap", children: container.status }),
|
|
104
|
+
/* @__PURE__ */ jsx("td", { className: "py-2.5 text-right whitespace-nowrap", children: /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1.5", children: [
|
|
108
105
|
isRunning && (isStopping ? /* @__PURE__ */ jsxs(
|
|
109
106
|
"button",
|
|
110
107
|
{
|
|
@@ -121,31 +121,30 @@ function ContainerRow({ container, onRequestStop, isStopping, isStarting }) {
|
|
|
121
121
|
|
|
122
122
|
return (
|
|
123
123
|
<tr className="border-t border-border">
|
|
124
|
-
<td className="py-2.5 pr-3">
|
|
124
|
+
<td className="py-2.5 pr-3 whitespace-nowrap">
|
|
125
125
|
<StateBadge state={container.state} />
|
|
126
126
|
</td>
|
|
127
|
-
<td className="py-2.5 pr-3 min-w-0">
|
|
128
|
-
<div className="text-sm font-medium truncate">{container.name}</div>
|
|
129
|
-
<div className="text-xs text-muted-foreground truncate">{imageName}</div>
|
|
127
|
+
<td className="py-2.5 pr-3 min-w-0 whitespace-nowrap">
|
|
128
|
+
<div className="text-sm font-medium truncate" title={imageName}>{container.name}</div>
|
|
130
129
|
</td>
|
|
131
|
-
<td className="py-2.5 pr-3 text-xs text-right hidden md:table-cell">
|
|
130
|
+
<td className="py-2.5 pr-3 text-xs text-right hidden md:table-cell whitespace-nowrap">
|
|
132
131
|
{isRunning && container.stats ? (
|
|
133
132
|
<span>{container.stats.cpu.toFixed(1)}%</span>
|
|
134
133
|
) : (
|
|
135
134
|
<span className="text-muted-foreground">—</span>
|
|
136
135
|
)}
|
|
137
136
|
</td>
|
|
138
|
-
<td className="py-2.5 pr-3 text-xs text-right hidden md:table-cell">
|
|
137
|
+
<td className="py-2.5 pr-3 text-xs text-right hidden md:table-cell whitespace-nowrap">
|
|
139
138
|
{isRunning && container.stats ? (
|
|
140
139
|
<span>{formatBytes(container.stats.memUsage)}</span>
|
|
141
140
|
) : (
|
|
142
141
|
<span className="text-muted-foreground">—</span>
|
|
143
142
|
)}
|
|
144
143
|
</td>
|
|
145
|
-
<td className="py-2.5 pr-3 text-xs text-muted-foreground hidden lg:table-cell">
|
|
144
|
+
<td className="py-2.5 pr-3 text-xs text-muted-foreground hidden lg:table-cell whitespace-nowrap">
|
|
146
145
|
{container.status}
|
|
147
146
|
</td>
|
|
148
|
-
<td className="py-2.5 text-right">
|
|
147
|
+
<td className="py-2.5 text-right whitespace-nowrap">
|
|
149
148
|
<div className="inline-flex items-center gap-1.5">
|
|
150
149
|
{isRunning && (
|
|
151
150
|
isStopping ? (
|
package/lib/tools/docker.js
CHANGED
|
@@ -162,7 +162,7 @@ async function runContainer({ containerName, image, env = [], workingDir, hostCo
|
|
|
162
162
|
* @param {boolean} [options.injectSecrets] - Inject agent job secrets into container env
|
|
163
163
|
* @returns {Promise<{containerId: string, containerName: string}>}
|
|
164
164
|
*/
|
|
165
|
-
async function runInteractiveContainer({ containerName, repo, branch, codingAgent, featureBranch, workspaceId, injectSecrets }) {
|
|
165
|
+
async function runInteractiveContainer({ containerName, repo, branch, codingAgent, featureBranch, workspaceId, injectSecrets, continueSession = true }) {
|
|
166
166
|
const agent = codingAgent || getConfig('CODING_AGENT') || 'claude-code';
|
|
167
167
|
const version = process.env.THEPOPEBOT_VERSION;
|
|
168
168
|
const image = `stephengpope/thepopebot:coding-agent-${agent}-${version}`;
|
|
@@ -184,6 +184,9 @@ async function runInteractiveContainer({ containerName, repo, branch, codingAgen
|
|
|
184
184
|
if (featureBranch) {
|
|
185
185
|
env.push(`FEATURE_BRANCH=${featureBranch}`);
|
|
186
186
|
}
|
|
187
|
+
if (continueSession) {
|
|
188
|
+
env.push(`CONTINUE_SESSION=1`);
|
|
189
|
+
}
|
|
187
190
|
|
|
188
191
|
// Inject agent job secrets when running in agent chat mode
|
|
189
192
|
if (injectSecrets) {
|
|
@@ -194,6 +197,9 @@ async function runInteractiveContainer({ containerName, repo, branch, codingAgen
|
|
|
194
197
|
env.push(`${key}=${value}`);
|
|
195
198
|
}
|
|
196
199
|
}
|
|
200
|
+
if (jobSecrets.length > 0) {
|
|
201
|
+
env.push(`AGENT_JOB_SECRETS=${JSON.stringify(Object.fromEntries(jobSecrets.map(s => [s.key, s.value])))}`);
|
|
202
|
+
}
|
|
197
203
|
}
|
|
198
204
|
|
|
199
205
|
const hostConfig = {};
|
|
@@ -338,7 +344,7 @@ function buildAgentAuthEnv(agent) {
|
|
|
338
344
|
* @param {boolean} [options.injectSecrets] - Inject agent job secrets into container env
|
|
339
345
|
* @returns {Promise<{containerId: string, containerName: string}>}
|
|
340
346
|
*/
|
|
341
|
-
async function runHeadlessContainer({ containerName, repo, branch, featureBranch, workspaceId, taskPrompt, mode = 'plan', codingAgent, systemPrompt, continueSession, injectSecrets }) {
|
|
347
|
+
async function runHeadlessContainer({ containerName, repo, branch, featureBranch, workspaceId, taskPrompt, mode = 'plan', codingAgent, systemPrompt, continueSession = true, injectSecrets }) {
|
|
342
348
|
const agent = codingAgent || getConfig('CODING_AGENT') || 'claude-code';
|
|
343
349
|
const version = process.env.THEPOPEBOT_VERSION;
|
|
344
350
|
const image = `stephengpope/thepopebot:coding-agent-${agent}-${version}`;
|
|
@@ -382,6 +388,9 @@ async function runHeadlessContainer({ containerName, repo, branch, featureBranch
|
|
|
382
388
|
env.push(`${key}=${value}`);
|
|
383
389
|
}
|
|
384
390
|
}
|
|
391
|
+
if (jobSecrets.length > 0) {
|
|
392
|
+
env.push(`AGENT_JOB_SECRETS=${JSON.stringify(Object.fromEntries(jobSecrets.map(s => [s.key, s.value])))}`);
|
|
393
|
+
}
|
|
385
394
|
}
|
|
386
395
|
|
|
387
396
|
const hostConfig = {};
|
|
@@ -831,6 +840,9 @@ async function runAgentJobContainer({ agentJobId, repo, branch, title, descripti
|
|
|
831
840
|
env.push(`${key}=${value}`);
|
|
832
841
|
}
|
|
833
842
|
}
|
|
843
|
+
if (jobSecrets.length > 0) {
|
|
844
|
+
env.push(`AGENT_JOB_SECRETS=${JSON.stringify(Object.fromEntries(jobSecrets.map(s => [s.key, s.value])))}`);
|
|
845
|
+
}
|
|
834
846
|
|
|
835
847
|
console.log(`[agent-job] id=${shortId} agent=${agent} image=${image} backendApi=${backendApi}`);
|
|
836
848
|
|
package/package.json
CHANGED
package/templates/docs/CLI.md
CHANGED
|
@@ -27,15 +27,9 @@ These set GitHub repository secrets/variables using the `gh` CLI. They read `GH_
|
|
|
27
27
|
|
|
28
28
|
| Command | Description |
|
|
29
29
|
|---------|-------------|
|
|
30
|
-
| `set-agent-secret KEY [VALUE]` | Set `AGENT_<KEY>` GitHub secret and update `.env` |
|
|
31
|
-
| `set-agent-llm-secret KEY [VALUE]` | Set `AGENT_LLM_<KEY>` GitHub secret |
|
|
32
30
|
| `set-var KEY [VALUE]` | Set a GitHub repository variable |
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- **`AGENT_`** — Protected secrets passed to Docker container, filtered from LLM bash env. Example: `AGENT_GH_TOKEN`, `AGENT_ANTHROPIC_API_KEY`
|
|
37
|
-
- **`AGENT_LLM_`** — LLM-accessible secrets, not filtered. Example: `AGENT_LLM_BRAVE_API_KEY`
|
|
38
|
-
- **No prefix** — Workflow-only secrets, never passed to container. Example: `GH_WEBHOOK_SECRET`
|
|
32
|
+
Agent job secrets are now managed through the admin UI (Settings > Agent Jobs > Secrets), stored encrypted in SQLite, and injected directly into Docker containers.
|
|
39
33
|
|
|
40
34
|
## Common Workflows
|
|
41
35
|
|
|
@@ -61,5 +55,5 @@ npx thepopebot reset config/CRONS.json # accept new template
|
|
|
61
55
|
```bash
|
|
62
56
|
npx thepopebot set-var LLM_PROVIDER openai
|
|
63
57
|
npx thepopebot set-var LLM_MODEL gpt-4o
|
|
64
|
-
|
|
58
|
+
# Set API keys via admin UI: Settings > Agent Jobs > Secrets
|
|
65
59
|
```
|
|
@@ -91,7 +91,7 @@ Restart your server after changes.
|
|
|
91
91
|
```bash
|
|
92
92
|
npx thepopebot set-var LLM_PROVIDER openai
|
|
93
93
|
npx thepopebot set-var LLM_MODEL gpt-4o
|
|
94
|
-
|
|
94
|
+
# Set API keys via admin UI: Settings > Agent Jobs > Secrets
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
### Per-Job Overrides
|
|
@@ -118,7 +118,7 @@ Point at any OpenAI-compatible endpoint (DeepSeek, Ollama, Together AI, etc.):
|
|
|
118
118
|
npx thepopebot set-var LLM_PROVIDER custom
|
|
119
119
|
npx thepopebot set-var LLM_MODEL deepseek-chat
|
|
120
120
|
npx thepopebot set-var CUSTOM_OPENAI_BASE_URL https://api.deepseek.com/v1
|
|
121
|
-
|
|
121
|
+
# Set CUSTOM_API_KEY via admin UI: Settings > Agent Jobs > Secrets
|
|
122
122
|
|
|
123
123
|
# Local custom (Ollama, LM Studio, etc.) — needs self-hosted runner
|
|
124
124
|
npx thepopebot set-var RUNS_ON self-hosted
|
|
@@ -129,20 +129,9 @@ npx thepopebot set-var CUSTOM_OPENAI_BASE_URL http://host.docker.internal:11434/
|
|
|
129
129
|
|
|
130
130
|
---
|
|
131
131
|
|
|
132
|
-
##
|
|
132
|
+
## Agent Job Secrets
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
| Prefix | Purpose | Visible to LLM? |
|
|
137
|
-
|--------|---------|------------------|
|
|
138
|
-
| `AGENT_` | Protected credentials (filtered from LLM bash env) | No |
|
|
139
|
-
| `AGENT_LLM_` | LLM-accessible credentials (skills, browser logins) | Yes |
|
|
140
|
-
| *(none)* | Workflow-only secrets | N/A |
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
npx thepopebot set-agent-secret GH_TOKEN ghp_xxx # Protected
|
|
144
|
-
npx thepopebot set-agent-llm-secret BRAVE_API_KEY xxx # LLM-accessible
|
|
145
|
-
```
|
|
134
|
+
Agent job secrets are managed through the admin UI (Settings > Agent Jobs > Secrets). They are stored encrypted in SQLite and injected as env vars into Docker containers. The agent can discover available secrets via the `get-secret` skill.
|
|
146
135
|
|
|
147
136
|
---
|
|
148
137
|
|
|
@@ -25,22 +25,9 @@ thepopebot includes these security measures by default:
|
|
|
25
25
|
4. SDKs (Anthropic, GitHub CLI) read their keys from `process.env` normally
|
|
26
26
|
5. The LLM cannot `echo $ANYTHING` — subprocess env is filtered
|
|
27
27
|
|
|
28
|
-
###
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|-----------------|----------|------------------|
|
|
32
|
-
| Infrastructure keys (`GH_TOKEN`, `ANTHROPIC_API_KEY`) | `set-agent-secret` | No — filtered from bash |
|
|
33
|
-
| Skill API keys, browser logins | `set-agent-llm-secret` | Yes — skills need these |
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# Protected (filtered from LLM)
|
|
37
|
-
npx thepopebot set-agent-secret GH_TOKEN ghp_xxx
|
|
38
|
-
npx thepopebot set-agent-secret ANTHROPIC_API_KEY sk-ant-xxx
|
|
39
|
-
|
|
40
|
-
# Accessible to LLM (not filtered)
|
|
41
|
-
npx thepopebot set-agent-llm-secret BROWSER_PASSWORD mypass123
|
|
42
|
-
npx thepopebot set-agent-llm-secret BRAVE_API_KEY xxx
|
|
43
|
-
```
|
|
28
|
+
### Agent Job Secrets
|
|
29
|
+
|
|
30
|
+
Agent job secrets are managed through the admin UI (Settings > Agent Jobs > Secrets). They are stored encrypted in SQLite and injected as env vars into Docker containers. The agent can discover available secrets via the `get-secret` skill.
|
|
44
31
|
|
|
45
32
|
---
|
|
46
33
|
|
package/templates/docs/SKILLS.md
CHANGED
|
@@ -21,9 +21,7 @@ These are activated out of the box:
|
|
|
21
21
|
|
|
22
22
|
| Skill | Description |
|
|
23
23
|
|-------|-------------|
|
|
24
|
-
| `
|
|
25
|
-
| `llm-secrets` | List available LLM-accessible credentials |
|
|
26
|
-
| `modify-self` | Modify the agent's own code, configuration, personality, or cron jobs |
|
|
24
|
+
| `get-secret` | List available LLM-accessible credentials |
|
|
27
25
|
|
|
28
26
|
## Available Skills
|
|
29
27
|
|
|
@@ -104,21 +102,7 @@ If bash + curl isn't sufficient, use Node.js with a `package.json`. Dependencies
|
|
|
104
102
|
|
|
105
103
|
## Credential Setup
|
|
106
104
|
|
|
107
|
-
If a skill needs an API key
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
# Set as LLM-accessible GitHub secret
|
|
111
|
-
npx thepopebot set-agent-llm-secret MY_API_KEY your-key-here
|
|
112
|
-
|
|
113
|
-
# Also add to .env for local development
|
|
114
|
-
echo "MY_API_KEY=your-key-here" >> .env
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
For multi-line secrets (e.g., JSON service account files), pipe via stdin:
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
npx thepopebot set-agent-llm-secret GOOGLE_CREDENTIALS < credentials.json
|
|
121
|
-
```
|
|
105
|
+
If a skill needs an API key, add it via the admin UI (Settings > Agent Jobs > Secrets). The secret will be injected as an env var into Docker containers. The agent can discover available secrets via the `get-secret` skill.
|
|
122
106
|
|
|
123
107
|
---
|
|
124
108
|
|
|
@@ -98,18 +98,7 @@ The `skills/active/` directory is shared by both agent backends via symlink brid
|
|
|
98
98
|
|
|
99
99
|
## Credential Setup
|
|
100
100
|
|
|
101
|
-
If a skill needs an API key,
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
npx thepopebot set-agent-llm-secret KEY_NAME value
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
This creates a GitHub secret with `AGENT_LLM_` prefix, exposed as an env var in the Docker container. Also add to `.env` for local development.
|
|
108
|
-
|
|
109
|
-
**Multi-line secrets** (e.g., JSON service account files):
|
|
110
|
-
```bash
|
|
111
|
-
npx thepopebot set-agent-llm-secret GOOGLE_CREDENTIALS < credentials.json
|
|
112
|
-
```
|
|
101
|
+
If a skill needs an API key, add it via the admin UI (Settings > Agent Jobs > Secrets). The secret will be injected as an env var into Docker containers. The agent can discover available secrets via the `get-secret` skill.
|
|
113
102
|
|
|
114
103
|
## Testing
|
|
115
104
|
|
|
@@ -74,7 +74,6 @@ ln -s ~/pi-skills/youtube-transcript .claude/skills/youtube-transcript
|
|
|
74
74
|
| Skill | Description |
|
|
75
75
|
|-------|-------------|
|
|
76
76
|
| [brave-search](brave-search/SKILL.md) | Web search and content extraction via Brave Search |
|
|
77
|
-
| [browser-tools](browser-tools/SKILL.md) | Interactive browser automation via Chrome DevTools Protocol |
|
|
78
77
|
| [gccli](gccli/SKILL.md) | Google Calendar CLI for events and availability |
|
|
79
78
|
| [gdcli](gdcli/SKILL.md) | Google Drive CLI for file management and sharing |
|
|
80
79
|
| [gmcli](gmcli/SKILL.md) | Gmail CLI for email, drafts, and labels |
|
|
@@ -105,7 +104,6 @@ Skills use project-root-relative paths (e.g., `skills/brave-search/search.js`).
|
|
|
105
104
|
Some skills require additional setup. Generally, the agent will walk you through that. But if not, here you go:
|
|
106
105
|
|
|
107
106
|
- **brave-search**: Requires Node.js. Run `npm install` in the skill directory.
|
|
108
|
-
- **browser-tools**: Requires Chrome and Node.js. Run `npm install` in the skill directory.
|
|
109
107
|
- **gccli**: Requires Node.js. Install globally with `npm install -g @mariozechner/gccli`.
|
|
110
108
|
- **gdcli**: Requires Node.js. Install globally with `npm install -g @mariozechner/gdcli`.
|
|
111
109
|
- **gmcli**: Requires Node.js. Install globally with `npm install -g @mariozechner/gmcli`.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: get-secret
|
|
3
3
|
description: List available LLM-accessible credentials. Use when you need API keys, passwords, or other secrets that have been made available to you.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# List Available Secrets
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
skills/
|
|
9
|
+
skills/get-secret/get-secret.js
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Shows the names of available secret keys (not values). Output example:
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* get-secret.js - List available agent job secret keys
|
|
5
5
|
*
|
|
6
|
-
* Usage:
|
|
6
|
+
* Usage: get-secret.js
|
|
7
7
|
*
|
|
8
|
-
* Lists the key names from
|
|
8
|
+
* Lists the key names from AGENT_JOB_SECRETS (not the values).
|
|
9
9
|
* To get a value, use: echo $KEY_NAME
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const secretsJson = process.env.
|
|
12
|
+
const secretsJson = process.env.AGENT_JOB_SECRETS;
|
|
13
13
|
|
|
14
14
|
if (!secretsJson) {
|
|
15
|
-
console.log('No
|
|
15
|
+
console.log('No AGENT_JOB_SECRETS configured.');
|
|
16
16
|
process.exit(0);
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -21,13 +21,13 @@ try {
|
|
|
21
21
|
const keys = Object.keys(parsed);
|
|
22
22
|
|
|
23
23
|
if (keys.length === 0) {
|
|
24
|
-
console.log('
|
|
24
|
+
console.log('AGENT_JOB_SECRETS is empty.');
|
|
25
25
|
} else {
|
|
26
26
|
console.log('Available secrets:');
|
|
27
27
|
keys.forEach(key => console.log(` - ${key}`));
|
|
28
28
|
console.log('\nTo get a value: echo $KEY_NAME');
|
|
29
29
|
}
|
|
30
30
|
} catch (e) {
|
|
31
|
-
console.error('Error parsing
|
|
31
|
+
console.error('Error parsing AGENT_JOB_SECRETS:', e.message);
|
|
32
32
|
process.exit(1);
|
|
33
33
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: modify-self
|
|
3
|
-
description: Use when a job requires modifying the agent's own code, configuration, personality, cron jobs, skills, or operating system files.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Modify Self
|
|
7
|
-
|
|
8
|
-
Before making any changes, read the project documentation for a full understanding of the system architecture:
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
cat CLAUDE.md
|
|
12
|
-
```
|