thepopebot 1.2.75-beta.12 → 1.2.75-beta.14
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/managed-paths.js +0 -4
- package/lib/ai/index.js +1 -1
- package/lib/chat/api.js +17 -1
- package/lib/chat/components/message.js +12 -5
- package/lib/chat/components/message.jsx +17 -5
- package/package.json +1 -1
- package/templates/.github/workflows/rebuild-event-handler.yml +3 -0
- package/templates/CLAUDE.md.template +31 -0
- package/templates/agent-job/CLAUDE.md.template +45 -22
- package/templates/agent-job/CRONS.json +0 -40
- package/templates/agent-job/SOUL.md +3 -3
- package/templates/agent-job/SYSTEM.md +41 -16
- package/templates/agents/.gitkeep +0 -0
- package/templates/agents/CLAUDE.md.template +5 -0
package/bin/managed-paths.js
CHANGED
|
@@ -4,13 +4,9 @@
|
|
|
4
4
|
// Paths ending with '/' are directories (all contents are managed).
|
|
5
5
|
export const MANAGED_PATHS = [
|
|
6
6
|
'.github/workflows/',
|
|
7
|
-
|
|
8
7
|
'docker-compose.yml',
|
|
9
8
|
'.dockerignore',
|
|
10
9
|
'.gitignore',
|
|
11
|
-
'agent-job/CLAUDE.md',
|
|
12
|
-
'event-handler/CLAUDE.md',
|
|
13
|
-
'skills/CLAUDE.md',
|
|
14
10
|
];
|
|
15
11
|
|
|
16
12
|
export function isManaged(relPath) {
|
package/lib/ai/index.js
CHANGED
|
@@ -385,7 +385,7 @@ async function autoTitle(threadId, firstMessage) {
|
|
|
385
385
|
|
|
386
386
|
const model = await createModel({ maxTokens: 250 });
|
|
387
387
|
const response = await model.withStructuredOutput(z.object({ title: z.string() })).invoke([
|
|
388
|
-
['system', '
|
|
388
|
+
['system', 'Title this chat in 2-5 words. Name the subject matter only. Never start with "User". Never describe what the user is doing — just the topic. Always produce a title, even for vague messages — infer the likely topic.'],
|
|
389
389
|
['human', firstMessage],
|
|
390
390
|
]);
|
|
391
391
|
if (response.title.trim()) {
|
package/lib/chat/api.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { auth } from '../auth/index.js';
|
|
2
2
|
import { chatStream } from '../ai/index.js';
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { getConfig } from '../config.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* POST handler for /stream/chat — streaming chat with session auth.
|
|
@@ -114,11 +115,26 @@ export async function POST(request) {
|
|
|
114
115
|
toolCallId: chunk.toolCallId,
|
|
115
116
|
toolName: chunk.toolName,
|
|
116
117
|
});
|
|
118
|
+
// Enrich coding_agent input with active agent identity from config
|
|
119
|
+
let input = chunk.args;
|
|
120
|
+
if (chunk.toolName === 'coding_agent') {
|
|
121
|
+
const agent = getConfig('CODING_AGENT') || 'claude-code';
|
|
122
|
+
const providerKeys = {
|
|
123
|
+
'claude-code': 'CODING_AGENT_CLAUDE_CODE_BACKEND',
|
|
124
|
+
'pi-coding-agent': 'CODING_AGENT_PI_PROVIDER',
|
|
125
|
+
'gemini-cli': 'CODING_AGENT_GEMINI_CLI_PROVIDER',
|
|
126
|
+
'codex-cli': 'CODING_AGENT_CODEX_CLI_PROVIDER',
|
|
127
|
+
'opencode': 'CODING_AGENT_OPENCODE_PROVIDER',
|
|
128
|
+
'kimi-cli': 'CODING_AGENT_KIMI_CLI_PROVIDER',
|
|
129
|
+
};
|
|
130
|
+
const backendApi = getConfig(providerKeys[agent]) || 'anthropic';
|
|
131
|
+
input = { ...chunk.args, codingAgent: agent, backendApi };
|
|
132
|
+
}
|
|
117
133
|
writer.write({
|
|
118
134
|
type: 'tool-input-available',
|
|
119
135
|
toolCallId: chunk.toolCallId,
|
|
120
136
|
toolName: chunk.toolName,
|
|
121
|
-
input
|
|
137
|
+
input,
|
|
122
138
|
});
|
|
123
139
|
|
|
124
140
|
} else if (chunk.type === 'tool-result') {
|
|
@@ -150,12 +150,19 @@ function ToolCall({ part, className }) {
|
|
|
150
150
|
/* @__PURE__ */ jsx(WrenchIcon, { size: 14, className: "text-muted-foreground shrink-0 mt-0.5" }),
|
|
151
151
|
/* @__PURE__ */ jsx("span", { className: "flex flex-col min-w-0 flex-1", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
152
152
|
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: displayName }),
|
|
153
|
-
|
|
153
|
+
(() => {
|
|
154
154
|
try {
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
158
|
-
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: [
|
|
155
|
+
const agent = part.input?.codingAgent;
|
|
156
|
+
const backend = part.input?.backendApi;
|
|
157
|
+
if (agent || backend) {
|
|
158
|
+
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: [agent, backend].filter(Boolean).join(" \xB7 ") });
|
|
159
|
+
}
|
|
160
|
+
if (isDone) {
|
|
161
|
+
const o = typeof part.output === "string" ? JSON.parse(part.output) : part.output;
|
|
162
|
+
const meta = Array.isArray(o) ? o.find((e) => e.type === "meta") : o;
|
|
163
|
+
if (meta?.codingAgent || meta?.backendApi) {
|
|
164
|
+
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: [meta.codingAgent, meta.backendApi].filter(Boolean).join(" \xB7 ") });
|
|
165
|
+
}
|
|
159
166
|
}
|
|
160
167
|
} catch {
|
|
161
168
|
}
|
|
@@ -154,17 +154,29 @@ function ToolCall({ part, className }) {
|
|
|
154
154
|
<span className="flex flex-col min-w-0 flex-1">
|
|
155
155
|
<span className="flex items-center gap-2">
|
|
156
156
|
<span className="font-medium text-foreground">{displayName}</span>
|
|
157
|
-
{
|
|
157
|
+
{(() => {
|
|
158
158
|
try {
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
159
|
+
// Read from input (available immediately) or output meta (historical chats)
|
|
160
|
+
const agent = part.input?.codingAgent;
|
|
161
|
+
const backend = part.input?.backendApi;
|
|
162
|
+
if (agent || backend) {
|
|
162
163
|
return (
|
|
163
164
|
<span className="text-xs text-muted-foreground">
|
|
164
|
-
{[
|
|
165
|
+
{[agent, backend].filter(Boolean).join(' · ')}
|
|
165
166
|
</span>
|
|
166
167
|
);
|
|
167
168
|
}
|
|
169
|
+
if (isDone) {
|
|
170
|
+
const o = typeof part.output === 'string' ? JSON.parse(part.output) : part.output;
|
|
171
|
+
const meta = Array.isArray(o) ? o.find(e => e.type === 'meta') : o;
|
|
172
|
+
if (meta?.codingAgent || meta?.backendApi) {
|
|
173
|
+
return (
|
|
174
|
+
<span className="text-xs text-muted-foreground">
|
|
175
|
+
{[meta.codingAgent, meta.backendApi].filter(Boolean).join(' · ')}
|
|
176
|
+
</span>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
168
180
|
} catch {}
|
|
169
181
|
return null;
|
|
170
182
|
})()}
|
package/package.json
CHANGED
|
@@ -48,6 +48,9 @@ jobs:
|
|
|
48
48
|
cd /project && npx --yes thepopebot@latest init --no-install
|
|
49
49
|
fi
|
|
50
50
|
|
|
51
|
+
# Install the new version into node_modules so local CLI stays current
|
|
52
|
+
cd /project && npm install
|
|
53
|
+
|
|
51
54
|
# Commit any template changes from init
|
|
52
55
|
git -C /project add -A
|
|
53
56
|
if ! git -C /project diff --cached --quiet; then
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
This is a [thepopebot](https://github.com/stephengpope/thepopebot) project.
|
|
4
|
+
|
|
5
|
+
## Directories
|
|
6
|
+
|
|
7
|
+
- **`agent-job/`** — Agent job configuration: system prompts (`SOUL.md`, `SYSTEM.md`), heartbeat prompt, and cron schedules (`CRONS.json`).
|
|
8
|
+
- **`agents/`** — Custom agent definitions. Each subdirectory defines an agent.
|
|
9
|
+
- **`event-handler/`** — Event handler configuration: chat system prompts, trigger definitions (`TRIGGERS.json`), cluster templates, and LiteLLM proxy config.
|
|
10
|
+
- **`skills/`** — Skill plugins. Activate by symlinking into `skills/active/`.
|
|
11
|
+
- **`data/`** — Runtime data (SQLite database, cluster state). Not checked into git.
|
|
12
|
+
- **`logs/`** — Agent job logs, organized by job ID. Not checked into git.
|
|
13
|
+
|
|
14
|
+
## Files
|
|
15
|
+
|
|
16
|
+
- **`docker-compose.yml`** — Container definitions for the event handler and LiteLLM proxy. Managed — do not edit.
|
|
17
|
+
- **`docker-compose.custom.yml`** — Your Docker Compose overrides. Merged with the main compose file.
|
|
18
|
+
- **`.env`** — Environment variables (API keys, secrets). Never committed to git.
|
|
19
|
+
|
|
20
|
+
## Managed Files
|
|
21
|
+
|
|
22
|
+
Some files are auto-synced by `npx thepopebot init` and will be overwritten on upgrade. Do not edit these:
|
|
23
|
+
|
|
24
|
+
- `.github/workflows/` — CI/CD workflows
|
|
25
|
+
- `docker-compose.yml`
|
|
26
|
+
- `.dockerignore`
|
|
27
|
+
- `.gitignore`
|
|
28
|
+
- `agent-job/CLAUDE.md`
|
|
29
|
+
- `agents/CLAUDE.md`
|
|
30
|
+
- `event-handler/CLAUDE.md`
|
|
31
|
+
- `skills/CLAUDE.md`
|
|
@@ -1,34 +1,57 @@
|
|
|
1
1
|
# agent-job/ — Agent Job Configuration
|
|
2
2
|
|
|
3
|
-
This directory contains
|
|
3
|
+
This directory contains your agent job configuration files — system prompts, scheduling, and self-monitoring.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Files
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- **`SOUL.md`** — Agent personality, identity, and values. Included in every agent job system prompt.
|
|
8
|
+
- **`SYSTEM.md`** — Runtime environment documentation injected into the agent's context.
|
|
9
|
+
- **`HEARTBEAT.md`** — Prompt for the agent's periodic heartbeat cron job.
|
|
10
|
+
- **`CRONS.json`** — Scheduled job definitions, loaded at server startup.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|------|---------|---------|
|
|
11
|
-
| `SOUL.md` | Docker agent | Agent personality, identity, and values. Included in agent job system prompts. |
|
|
12
|
-
| `SYSTEM.md` | Docker agent | Runtime environment documentation injected into the agent's context. |
|
|
13
|
-
| `HEARTBEAT.md` | Heartbeat cron | Self-monitoring prompt for the agent's periodic heartbeat job. |
|
|
12
|
+
## Editing CRONS.json
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
`CRONS.json` is a JSON array of cron job objects. Each entry needs a `name`, `schedule` (cron expression), `type`, and `enabled` flag.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|------|---------|
|
|
19
|
-
| `CRONS.json` | Scheduled job definitions — loaded at server startup by `node-cron`. |
|
|
16
|
+
There are three action types:
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
**`agent`** — Launches a Docker agent container to execute an LLM task.
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"name": "heartbeat",
|
|
23
|
+
"schedule": "*/30 * * * *",
|
|
24
|
+
"type": "agent",
|
|
25
|
+
"job": "Read agent-job/HEARTBEAT.md and complete the tasks described there.",
|
|
26
|
+
"enabled": false
|
|
27
|
+
}
|
|
28
|
+
```
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|--------|-------------|
|
|
27
|
-
| `{{ filepath.md }}` | Include another file (path relative to project root, recursive with circular detection) |
|
|
28
|
-
| `{{datetime}}` | Current ISO timestamp |
|
|
29
|
-
| `{{skills}}` | Dynamic bullet list of active skill descriptions from `skills/active/*/SKILL.md` frontmatter |
|
|
30
|
+
Optional: add `"llm_provider"` and `"llm_model"` to override the default LLM for that job.
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
**`command`** — Runs a shell command on the event handler (working directory: project root).
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"name": "ping",
|
|
37
|
+
"schedule": "*/1 * * * *",
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "echo \"pong!\"",
|
|
40
|
+
"enabled": true
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**`webhook`** — Makes an HTTP request. `POST` (default) sends `vars` as the body; `GET` skips the body.
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"name": "health-check",
|
|
49
|
+
"schedule": "*/10 * * * *",
|
|
50
|
+
"type": "webhook",
|
|
51
|
+
"url": "https://example.com/health",
|
|
52
|
+
"method": "GET",
|
|
53
|
+
"enabled": false
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Optional webhook fields: `"method"` (default `POST`), `"headers"`, `"vars"`.
|
|
@@ -6,51 +6,11 @@
|
|
|
6
6
|
"job": "Read the file at agent-job/HEARTBEAT.md and complete the tasks described there.",
|
|
7
7
|
"enabled": false
|
|
8
8
|
},
|
|
9
|
-
{
|
|
10
|
-
"name": "daily-check",
|
|
11
|
-
"schedule": "0 9 * * *",
|
|
12
|
-
"type": "agent",
|
|
13
|
-
"job": "Check for dependency updates in package.json and report any outdated packages.",
|
|
14
|
-
"enabled": false
|
|
15
|
-
},
|
|
16
9
|
{
|
|
17
10
|
"name": "ping",
|
|
18
11
|
"schedule": "*/1 * * * *",
|
|
19
12
|
"type": "command",
|
|
20
13
|
"command": "echo \"pong!\"",
|
|
21
14
|
"enabled": true
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"name": "cleanup-logs",
|
|
25
|
-
"schedule": "0 0 * * 0",
|
|
26
|
-
"type": "command",
|
|
27
|
-
"command": "ls -la logs/",
|
|
28
|
-
"enabled": false
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"name": "ping-status",
|
|
32
|
-
"schedule": "*/5 * * * *",
|
|
33
|
-
"type": "webhook",
|
|
34
|
-
"url": "https://example.com/status",
|
|
35
|
-
"method": "POST",
|
|
36
|
-
"vars": { "source": "heartbeat" },
|
|
37
|
-
"enabled": false
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
"name": "health-check",
|
|
41
|
-
"schedule": "*/10 * * * *",
|
|
42
|
-
"type": "webhook",
|
|
43
|
-
"url": "https://example.com/health",
|
|
44
|
-
"method": "GET",
|
|
45
|
-
"enabled": false
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"name": "daily-check-openai",
|
|
49
|
-
"schedule": "0 9 * * *",
|
|
50
|
-
"type": "agent",
|
|
51
|
-
"job": "Check for dependency updates in package.json and report any outdated packages.",
|
|
52
|
-
"llm_provider": "openai",
|
|
53
|
-
"llm_model": "gpt-4o",
|
|
54
|
-
"enabled": false
|
|
55
15
|
}
|
|
56
16
|
]
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Agent Job Soul
|
|
2
2
|
|
|
3
3
|
## Identity
|
|
4
4
|
|
|
5
|
-
You are a diligent and capable AI worker. You approach tasks with focus, patience, and craftsmanship.
|
|
5
|
+
You are a diligent and capable AI worker doing an job. You approach tasks with focus, patience, and craftsmanship.
|
|
6
6
|
|
|
7
7
|
## Personality Traits
|
|
8
8
|
|
|
9
9
|
- **Methodical**: You work through problems systematically, step by step
|
|
10
10
|
- **Reliable**: You follow through on commitments and complete what I start
|
|
11
11
|
- **Curious**: You explore and learn from the codebase I work with
|
|
12
|
-
- **Working Style**: You
|
|
12
|
+
- **Working Style**: You plan before acting
|
|
13
13
|
|
|
14
14
|
## Values
|
|
15
15
|
|
|
@@ -1,30 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Agent Job Environment
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
You are an autonomous AI agent running inside a Docker container on thepopebot.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Runtime Environment
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Your workspace is `/home/coding-agent/workspace` — a live git repository. Use `/tmp` for working files — downloads, intermediate data, scripts, generated files. `/tmp` is outside the repo and nothing there gets committed. If a tool downloads a file to `/tmp`, leave it there and reference it directly.
|
|
8
8
|
|
|
9
|
-
You
|
|
10
|
-
- You have full access to the machine and anything it can do to get the job done.
|
|
9
|
+
Everything in the workspace is automatically committed and pushed when your job finishes. You do not control this. Be intentional about what you put here — **any file you create, move, or download into the workspace WILL be committed.**
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
Current datetime: {{datetime}}
|
|
13
12
|
|
|
14
|
-
##
|
|
13
|
+
## Directory Layout
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
- `agents/` — Agent definitions. Each subdirectory defines an agent with its own prompts.
|
|
16
|
+
- `agent-job/` — Runtime config: system prompts (`SOUL.md`, `SYSTEM.md`), cron schedules (`CRONS.json`), heartbeat prompt.
|
|
17
|
+
- `event-handler/` — Event handler config. Do not edit — managed by the event handler.
|
|
18
|
+
- `skills/` — Skill plugins. Active skills are symlinked into `skills/active/`.
|
|
19
|
+
- `data/`, `logs/` — Runtime data and job logs.
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
## What You Can Edit
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
- `agent-job/CRONS.json` — Add, remove, or change scheduled jobs
|
|
24
|
+
- `agents/` — Create or remove agent definitions
|
|
25
|
+
- `skills/active/` — Activate or deactivate skills via symlinks
|
|
26
|
+
- Agent prompt files (`.md`) in `agent-job/` and `agents/`
|
|
27
|
+
- Reports and output files
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
## What You Cannot Edit
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
- `event-handler/` — Chat prompts, triggers, clusters, LiteLLM config
|
|
32
|
+
- `docker-compose.yml`, `.dockerignore`, `.gitignore` — Managed infrastructure files
|
|
33
|
+
- `.env` — Environment secrets
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
## Self-Modification
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
**Add an agent** — Create `agents/<name>/` with a `prompts/` subfolder, add a cron entry in `agent-job/CRONS.json` pointing to the prompt file, update `agents/CLAUDE.md` to document it, update root `CLAUDE.md` to reflect the new agent.
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
**Remove an agent** — Delete the `agents/<name>/` folder, remove its cron entries, update `agents/CLAUDE.md` and root `CLAUDE.md`.
|
|
40
|
+
|
|
41
|
+
**Change a schedule** — Edit `agent-job/CRONS.json` (cron expressions, enable/disable).
|
|
42
|
+
|
|
43
|
+
**Activate a skill** — Symlink from `skills/<name>/` into `skills/active/`, update root `CLAUDE.md`.
|
|
44
|
+
|
|
45
|
+
**Deactivate a skill** — Remove the symlink from `skills/active/`, update root `CLAUDE.md`.
|
|
46
|
+
|
|
47
|
+
**Keep CLAUDE.md files current** — When you change the structure of the instance (add/remove agents, change schedules, activate skills), update the root `CLAUDE.md` and any affected folder-level `CLAUDE.md` files so the next agent has an accurate picture.
|
|
48
|
+
|
|
49
|
+
## Active Skills
|
|
50
|
+
|
|
51
|
+
{{skills}}
|
|
52
|
+
|
|
53
|
+
## Orientation
|
|
54
|
+
|
|
55
|
+
Read the root `CLAUDE.md` for instance-specific context — what agents are deployed, what this instance is for. Read the `CLAUDE.md` in each folder you work in for local conventions.
|
|
File without changes
|