@pleaseai/agent 0.1.16

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.
Files changed (4) hide show
  1. package/LICENSE +112 -0
  2. package/README.md +738 -0
  3. package/dist/index.js +28403 -0
  4. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,738 @@
1
+ # Agent Please
2
+
3
+ English | [한국어](README.ko.md) | [日本語](README.ja.md) | [简体中文](README.zh-CN.md)
4
+
5
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=pleaseai_agent-please&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=pleaseai_agent-please) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=pleaseai_agent-please&metric=bugs)](https://sonarcloud.io/summary/new_code?id=pleaseai_agent-please) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=pleaseai_agent-please&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=pleaseai_agent-please) [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=pleaseai_agent-please&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=pleaseai_agent-please)
6
+ [![codecov](https://codecov.io/gh/pleaseai/agent-please/graph/badge.svg?token=do858Z1lsI)](https://codecov.io/gh/pleaseai/agent-please)
7
+
8
+ Agent Please turns issue tracker tasks into isolated, autonomous implementation runs — managing work
9
+ instead of supervising coding agents.
10
+
11
+ > **Warning**: Agent Please is an engineering preview for use in trusted environments.
12
+
13
+ ## Table of Contents
14
+
15
+ - [Overview](#overview)
16
+ - [Key Differences from Symphony](#key-differences-from-symphony)
17
+ - [Features](#features)
18
+ - [Architecture](#architecture)
19
+ - [Quick Start](#quick-start)
20
+ - [Prerequisites](#prerequisites)
21
+ - [Install](#install)
22
+ - [Configure](#configure)
23
+ - [Run](#run)
24
+ - [WORKFLOW.md Configuration](#workflowmd-configuration)
25
+ - [Full Front Matter Schema](#full-front-matter-schema)
26
+ - [Template Variables](#template-variables)
27
+ - [CLI Usage](#cli-usage)
28
+ - [GitHub App Authentication](#github-app-authentication)
29
+ - [Setting up GitHub App credentials](#setting-up-github-app-credentials)
30
+ - [Validation](#validation)
31
+ - [Slack Notifications](#slack-notifications)
32
+ - [Slack App Setup](#slack-app-setup)
33
+ - [Trust and Safety](#trust-and-safety)
34
+ - [Permission Modes](#permission-modes)
35
+ - [Workspace Isolation](#workspace-isolation)
36
+ - [Recommendations](#recommendations)
37
+ - [License](#license)
38
+
39
+ ## Overview
40
+
41
+ Agent Please is a long-running TypeScript service that:
42
+
43
+ 1. Polls an issue tracker (GitHub Projects v2 or Asana) for tasks in configured active states.
44
+ 2. Creates an isolated workspace directory for each eligible issue.
45
+ 3. Launches a Claude Code agent session inside that workspace with a rendered prompt.
46
+ 4. Monitors the session, handles retries, and reconciles issue state on each poll cycle.
47
+
48
+ It is a TypeScript implementation of the [Symphony specification](vendor/symphony/SPEC.md),
49
+ adapted for GitHub Projects v2 / Asana and Claude Code instead of Linear and Codex.
50
+
51
+ For full technical details, see [SPEC.md](SPEC.md).
52
+
53
+ ## Key Differences from Symphony
54
+
55
+ | | Symphony (reference) | Agent Please |
56
+ |---|---|---|
57
+ | Issue Tracker | Linear | GitHub Projects v2 & Asana (under development) |
58
+ | Coding Agent | Codex (app-server mode) | Claude Code CLI |
59
+ | Language | Elixir/OTP | TypeScript + Bun |
60
+ | Tracker Auth | `LINEAR_API_KEY` | `GITHUB_TOKEN`, GitHub App credentials, or `ASANA_ACCESS_TOKEN` |
61
+ | Project Config | `project_slug` | `owner` + `project_number` (GitHub Projects v2) or `project_gid` (Asana) |
62
+ | Issue States | Linear workflow states | GitHub Projects v2 Status field / Asana sections |
63
+ | Agent Protocol | JSON-RPC over stdio | `@anthropic-ai/claude-agent-sdk` |
64
+ | Permission Model | Codex approval/sandbox policies | Claude Code `--permission-mode` |
65
+
66
+ ## Features
67
+
68
+ - **Multi-tracker support** — Dispatch work from GitHub Projects v2 items or Asana tasks (under development) on a
69
+ fixed cadence.
70
+ - **GitHub App authentication** — Authenticate the GitHub tracker with a GitHub App installation
71
+ token (`app_id` + `private_key` + `installation_id`) instead of a PAT, for fine-grained
72
+ permissions and higher API rate limits.
73
+ - **Assignee & label filters** — Filter eligible issues by assignee and/or label. Multiple values
74
+ within each filter use OR logic; assignee and label filters are ANDed when both are specified.
75
+ Applies at dispatch time only — already-running issues are unaffected. Configured per-tracker
76
+ in `WORKFLOW.md`.
77
+ - **Isolated workspaces** — Each issue gets a dedicated directory; workspaces persist across runs.
78
+ - **`WORKFLOW.md` config** — Version agent prompt and runtime settings alongside your code.
79
+ - **Bounded concurrency** — Global and per-state concurrent agent limits.
80
+ - **Retry with backoff** — Exponential backoff on failures; short continuation retry on clean exit.
81
+ - **Dynamic config reload** — Edit `WORKFLOW.md` and changes apply without restarting the service.
82
+ - **Workspace hooks** — Shell scripts run at `after_create`, `before_run`, `after_run`, and
83
+ `before_remove` lifecycle events.
84
+ - **Structured logging** — Operator-visible logs with stable `key=value` format.
85
+ - **Slack notifications** — @mention the bot in Slack to get orchestrator status. Uses
86
+ [Chat SDK](https://chat-sdk.dev/) Slack adapter.
87
+ - **Optional HTTP dashboard** — Enable with `--port` for runtime status and JSON API.
88
+
89
+ ## Architecture
90
+
91
+ ```
92
+ WORKFLOW.md
93
+ |
94
+ v
95
+ Config Layer ──> Orchestrator ──> Workspace Manager ──> Agent Runner (Claude Code)
96
+ | |
97
+ v v
98
+ Issue Tracker Client Isolated workspace/
99
+ (GitHub GraphQL API or per-issue directory
100
+ Asana REST API,
101
+ polling + reconciliation)
102
+ |
103
+ v
104
+ Status Surface (optional HTTP dashboard / structured logs)
105
+ ```
106
+
107
+ Components:
108
+
109
+ - **Workflow Loader** — Parses `WORKFLOW.md` YAML front matter and prompt template body.
110
+ - **Config Layer** — Typed getters with env-var indirection and built-in defaults.
111
+ - **Issue Tracker Client** — Fetches candidate issues, reconciles running-issue states. Supports
112
+ GitHub Projects v2 (GraphQL API) and Asana (REST API) adapters.
113
+ - **Orchestrator** — Owns in-memory state; drives the poll/dispatch/retry loop.
114
+ - **Workspace Manager** — Creates, reuses, and cleans per-issue workspaces; runs hooks.
115
+ - **Agent Runner** — Launches Claude Code, streams events back to the orchestrator.
116
+ - **Status Surface** — Optional terminal view and HTTP API for operator visibility.
117
+
118
+ See [SPEC.md](SPEC.md) for the full specification.
119
+
120
+ ## Quick Start
121
+
122
+ ### Prerequisites
123
+
124
+ - **Bun** (see [bun.sh](https://bun.sh) for installation)
125
+ - **Claude Code CLI** (see the [official installation guide](https://docs.anthropic.com/en/docs/claude-code))
126
+ - **GitHub token** (`GITHUB_TOKEN`) with access to the target project, **or** **GitHub App credentials**
127
+ (`GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_APP_INSTALLATION_ID`) — see [GitHub App Authentication](#github-app-authentication),
128
+ **or** **Asana access token** (`ASANA_ACCESS_TOKEN`) (under development)
129
+
130
+ ### Install
131
+
132
+ ```bash
133
+ git clone https://github.com/pleaseai/agent-please.git
134
+ cd agent-please
135
+ bun install
136
+ bun run build
137
+ ```
138
+
139
+ ### Configure
140
+
141
+ Create a `WORKFLOW.md` in your target repository. Two examples are shown below.
142
+ See also the [example WORKFLOW.md](https://github.com/pleaseai/workflow/blob/main/WORKFLOW.md) for a real-world reference.
143
+
144
+ #### GitHub Projects v2 (PAT)
145
+
146
+ See also the [example GitHub Project](https://github.com/orgs/pleaseai/projects/2) for a real-world reference.
147
+
148
+ ```markdown
149
+ ---
150
+ tracker:
151
+ kind: github_projects
152
+ api_key: $GITHUB_TOKEN
153
+ owner: your-org
154
+ project_number: 42
155
+ active_statuses:
156
+ - Todo
157
+ - In Progress
158
+ - Merging
159
+ - Rework
160
+ terminal_statuses:
161
+ - Closed
162
+ - Cancelled
163
+ - Canceled
164
+ - Duplicate
165
+ - Done
166
+ watched_statuses:
167
+ - Human Review
168
+
169
+ polling:
170
+ interval_ms: 30000
171
+
172
+ workspace:
173
+ root: ~/agent-please_workspaces
174
+
175
+ hooks:
176
+ after_create: |
177
+ git clone https://github.com/your-org/your-repo.git .
178
+ bun install
179
+
180
+ agent:
181
+ max_concurrent_agents: 3
182
+ max_turns: 20
183
+
184
+ claude:
185
+ permission_mode: acceptEdits
186
+ # setting_sources: [] # default: [project, local, user]; set [] for SDK isolation mode
187
+ turn_timeout_ms: 3600000
188
+ ---
189
+
190
+ You are working on a GitHub issue for the repository `your-org/your-repo`.
191
+
192
+ Issue {{ issue.identifier }}: {{ issue.title }}
193
+
194
+ {{ issue.description }}
195
+
196
+ {% if issue.blocked_by.size > 0 %}
197
+ Blocked by:
198
+ {% for blocker in issue.blocked_by %}
199
+ - {{ blocker.identifier }} ({{ blocker.state }})
200
+ {% endfor %}
201
+ {% endif %}
202
+
203
+ {% if attempt %}
204
+ This is attempt #{{ attempt }}. Review any prior work in the workspace before continuing.
205
+ {% endif %}
206
+
207
+ Your task:
208
+ 1. Understand the issue requirements.
209
+ 2. Implement the requested changes.
210
+ 3. Write or update tests as needed.
211
+ 4. Open a pull request and move this issue to `Human Review`.
212
+ ```
213
+
214
+ #### GitHub Projects v2 (GitHub App)
215
+
216
+ Use GitHub App credentials instead of a PAT for fine-grained permissions and higher API rate limits:
217
+
218
+ ```markdown
219
+ ---
220
+ tracker:
221
+ kind: github_projects
222
+ app_id: $GITHUB_APP_ID
223
+ private_key: $GITHUB_APP_PRIVATE_KEY
224
+ installation_id: $GITHUB_APP_INSTALLATION_ID
225
+ owner: your-org
226
+ project_number: 42
227
+ active_statuses:
228
+ - Todo
229
+ - In Progress
230
+ - Merging
231
+ - Rework
232
+ terminal_statuses:
233
+ - Closed
234
+ - Cancelled
235
+ - Canceled
236
+ - Duplicate
237
+ - Done
238
+ watched_statuses:
239
+ - Human Review
240
+
241
+ polling:
242
+ interval_ms: 30000
243
+
244
+ workspace:
245
+ root: ~/agent-please_workspaces
246
+
247
+ hooks:
248
+ after_create: |
249
+ git clone https://github.com/your-org/your-repo.git .
250
+ bun install
251
+
252
+ agent:
253
+ max_concurrent_agents: 3
254
+ max_turns: 20
255
+
256
+ claude:
257
+ permission_mode: acceptEdits
258
+ # setting_sources: [] # default: [project, local, user]; set [] for SDK isolation mode
259
+ turn_timeout_ms: 3600000
260
+ ---
261
+
262
+ You are working on a GitHub issue for the repository `your-org/your-repo`.
263
+
264
+ Issue {{ issue.identifier }}: {{ issue.title }}
265
+
266
+ {{ issue.description }}
267
+
268
+ {% if issue.blocked_by.size > 0 %}
269
+ Blocked by:
270
+ {% for blocker in issue.blocked_by %}
271
+ - {{ blocker.identifier }} ({{ blocker.state }})
272
+ {% endfor %}
273
+ {% endif %}
274
+
275
+ {% if attempt %}
276
+ This is attempt #{{ attempt }}. Review any prior work in the workspace before continuing.
277
+ {% endif %}
278
+
279
+ Your task:
280
+ 1. Understand the issue requirements.
281
+ 2. Implement the requested changes.
282
+ 3. Write or update tests as needed.
283
+ 4. Open a pull request and move this issue to `Human Review`.
284
+ ```
285
+
286
+ #### Asana (under development)
287
+
288
+ > **Note**: Asana support is under development. The configuration below is a preview and may change.
289
+
290
+ ```markdown
291
+ ---
292
+ tracker:
293
+ kind: asana
294
+ api_key: $ASANA_ACCESS_TOKEN
295
+ project_gid: "1234567890123456"
296
+ active_sections:
297
+ - In Progress
298
+ terminal_sections:
299
+ - Done
300
+ - Cancelled
301
+
302
+ polling:
303
+ interval_ms: 30000
304
+
305
+ workspace:
306
+ root: ~/agent-please_workspaces
307
+
308
+ hooks:
309
+ after_create: |
310
+ git clone https://github.com/your-org/your-repo.git .
311
+ bun install
312
+
313
+ agent:
314
+ max_concurrent_agents: 3
315
+ max_turns: 20
316
+
317
+ claude:
318
+ permission_mode: acceptEdits
319
+ # setting_sources: [] # default: [project, local, user]; set [] for SDK isolation mode
320
+ turn_timeout_ms: 3600000
321
+ ---
322
+
323
+ You are working on an Asana task for the project.
324
+
325
+ Task: {{ issue.title }}
326
+
327
+ {{ issue.description }}
328
+
329
+ {% if issue.blocked_by.size > 0 %}
330
+ Blocked by:
331
+ {% for blocker in issue.blocked_by %}
332
+ - {{ blocker.identifier }} ({{ blocker.state }})
333
+ {% endfor %}
334
+ {% endif %}
335
+
336
+ {% if attempt %}
337
+ This is attempt #{{ attempt }}. Review any prior work in the workspace before continuing.
338
+ {% endif %}
339
+
340
+ Your task:
341
+ 1. Understand the task requirements.
342
+ 2. Implement the requested changes.
343
+ 3. Write or update tests as needed.
344
+ 4. Open a pull request and move this task to the review section (e.g. `Human Review`).
345
+ ```
346
+
347
+ ### Run
348
+
349
+ ```bash
350
+ # Set your tracker token (GitHub PAT)
351
+ export GITHUB_TOKEN=ghp_your_token_here
352
+ # or (GitHub App)
353
+ export GITHUB_APP_ID=12345
354
+ export GITHUB_APP_PRIVATE_KEY="$(cat path/to/private-key.pem)"
355
+ export GITHUB_APP_INSTALLATION_ID=67890
356
+ # or (Asana — under development)
357
+ export ASANA_ACCESS_TOKEN=your_token_here
358
+
359
+ # Run Agent Please against a WORKFLOW.md in the current directory
360
+ bunx agent-please
361
+
362
+ # Or specify a WORKFLOW.md path
363
+ bunx agent-please /path/to/WORKFLOW.md
364
+
365
+ # Enable the optional HTTP dashboard on port 3000
366
+ bunx agent-please --port 3000
367
+ ```
368
+
369
+ ## WORKFLOW.md Configuration
370
+
371
+ `WORKFLOW.md` is the single source of truth for Agent Please's runtime behavior. It combines a YAML
372
+ front matter configuration block with a Markdown prompt template body.
373
+
374
+ ### Full Front Matter Schema
375
+
376
+ ```yaml
377
+ ---
378
+ tracker:
379
+ kind: github_projects # Required: "github_projects" or "asana"
380
+
381
+ # --- GitHub Projects v2 fields (when kind == "github_projects") ---
382
+ api_key: $GITHUB_TOKEN # Required: token or $ENV_VAR
383
+ endpoint: https://api.github.com # Optional: override GitHub API base URL
384
+ owner: your-org # Required: GitHub organization or user login
385
+ project_number: 42 # Required: GitHub Projects v2 project number
386
+ project_id: PVT_kwDOxxxxx # Optional: project node ID (bypasses owner+project_number lookup)
387
+ active_statuses: # Optional: default ["Todo", "In Progress", "Merging", "Rework"]
388
+ - Todo
389
+ - In Progress
390
+ - Merging
391
+ - Rework
392
+ terminal_statuses: # Optional: default ["Closed", "Cancelled", "Canceled", "Duplicate", "Done"]
393
+ - Closed
394
+ - Cancelled
395
+ - Canceled
396
+ - Duplicate
397
+ - Done
398
+ watched_statuses: # Optional: states polled for dispatch on review activity. Default ["Human Review"]
399
+ - Human Review
400
+ # GitHub App authentication (alternative to api_key — all three required together):
401
+ # app_id: $GITHUB_APP_ID # Optional: GitHub App ID (integer or $ENV_VAR)
402
+ # private_key: $GITHUB_APP_PRIVATE_KEY # Optional: GitHub App private key PEM or $ENV_VAR
403
+ # installation_id: $GITHUB_APP_INSTALLATION_ID # Optional: installation ID (integer or $ENV_VAR)
404
+
405
+ # --- Asana fields (when kind == "asana") --- UNDER DEVELOPMENT
406
+ # api_key: $ASANA_ACCESS_TOKEN # Required: token or $ENV_VAR
407
+ # endpoint: https://app.asana.com/api/1.0 # Optional: override Asana API base URL
408
+ # project_gid: "1234567890123456" # Required: Asana project GID
409
+ # active_sections: # Optional: default ["To Do", "In Progress"]
410
+ # - In Progress
411
+ # terminal_sections: # Optional: default ["Done", "Cancelled"]
412
+ # - Done
413
+ # - Cancelled
414
+
415
+ # --- Shared filter fields (both trackers) ---
416
+ # filter:
417
+ # assignee: user1, user2 # Optional: CSV or YAML array; case-insensitive OR match
418
+ # # (unassigned issues are excluded when this filter is set)
419
+ # label: bug, feature # Optional: CSV or YAML array; case-insensitive OR match
420
+ # Both filters AND together when both are specified. Applies at dispatch time only.
421
+
422
+ polling:
423
+ interval_ms: 30000 # Optional: poll cadence in ms, default 30000
424
+
425
+ workspace:
426
+ root: ~/agent-please_workspaces # Optional: default <tmpdir>/agent-please_workspaces
427
+
428
+ hooks:
429
+ after_create: | # Optional: run once when workspace is first created
430
+ git clone https://github.com/your-org/your-repo.git .
431
+ before_run: | # Optional: run before each agent attempt
432
+ git pull --rebase
433
+ after_run: | # Optional: run after each agent attempt
434
+ echo "Run completed"
435
+ before_remove: | # Optional: run before workspace deletion
436
+ echo "Cleaning up"
437
+ timeout_ms: 60000 # Optional: hook timeout in ms, default 60000
438
+
439
+ agent:
440
+ max_concurrent_agents: 10 # Optional: global concurrency limit, default 10
441
+ max_turns: 20 # Optional: max turns per agent run, default 20
442
+ max_retry_backoff_ms: 300000 # Optional: max retry delay in ms, default 300000
443
+ max_concurrent_agents_by_state: # Optional: per-state concurrency limits
444
+ in progress: 5
445
+
446
+ claude:
447
+ command: claude # Optional: Claude Code CLI command, default "claude"
448
+ model: claude-sonnet-4-5-20250514 # Optional: override Claude model. Default: CLI default
449
+ effort: high # Optional: reasoning depth — 'low', 'medium', 'high', or 'max'. Default 'high'.
450
+ permission_mode: acceptEdits # Optional: one of 'default', 'acceptEdits', 'bypassPermissions'. Defaults to 'bypassPermissions'.
451
+ allowed_tools: # Optional: restrict available tools
452
+ - Read
453
+ - Write
454
+ - Bash
455
+ setting_sources: # Optional: filesystem settings to load. Default: [project, local, user]
456
+ - project # load .claude/settings.json + CLAUDE.md from the workspace directory
457
+ - local # load .claude/settings.local.json from the workspace directory
458
+ - user # load ~/.claude/settings.json + global CLAUDE.md
459
+ # Only "project", "local", and "user" are valid — other values are ignored
460
+ turn_timeout_ms: 3600000 # Optional: per-turn timeout in ms, default 3600000
461
+ read_timeout_ms: 5000 # Optional: initial subprocess read timeout in ms, default 5000
462
+ stall_timeout_ms: 300000 # Optional: stall detection timeout, default 300000
463
+ system_prompt: "custom prompt" # Optional: custom system prompt string. Default: built-in claude_code preset
464
+ settings:
465
+ attribution:
466
+ commit: "🙏 Generated with [Agent Please](https://github.com/pleaseai/agent-please)" # Optional: appended to git commit messages. Defaults to Agent Please link.
467
+ pr: "🙏 Generated with [Agent Please](https://github.com/pleaseai/agent-please)" # Optional: appended to PR descriptions. Defaults to Agent Please link.
468
+
469
+ # worker: # Optional: SSH worker support (experimental)
470
+ # ssh_hosts: # List of SSH host aliases for remote execution
471
+ # - worker-1
472
+ # - worker-2
473
+ # max_concurrent_agents_per_host: 5 # Max agents per SSH host
474
+
475
+ # observability: # Optional: TUI dashboard settings
476
+ # dashboard_enabled: true # Enable TUI dashboard, default true
477
+ # refresh_ms: 1000 # Dashboard data refresh interval, default 1000
478
+ # render_interval_ms: 16 # TUI render interval, default 16
479
+
480
+ server:
481
+ port: 3000 # Optional: enable HTTP dashboard on this port
482
+ host: "127.0.0.1" # Optional: bind address, default "127.0.0.1"
483
+ # Webhook endpoints:
484
+ # GitHub: POST /api/webhooks/github (requires server.webhook.secret)
485
+ # Slack: POST /api/webhooks/slack (requires SLACK_BOT_TOKEN + SLACK_SIGNING_SECRET env vars)
486
+ ---
487
+
488
+ Your prompt template goes here. Available variables:
489
+
490
+ - {{ issue.id }} — Tracker-internal issue ID
491
+ - {{ issue.identifier }} — Human-readable identifier (e.g. "#42" or task GID)
492
+ - {{ issue.title }} — Issue title
493
+ - {{ issue.description }} — Issue body/description
494
+ - {{ issue.state }} — Current tracker state name
495
+ - {{ issue.url }} — Issue URL
496
+ - {{ issue.assignees }} — Array of assignee logins (GitHub) or emails (Asana)
497
+ - {{ issue.labels }} — Array of label strings (normalized to lowercase)
498
+ - {{ issue.blocked_by }} — Array of blocker refs (each has id, identifier, state)
499
+ - {{ issue.branch_name }} — PR head branch name (for PullRequest items) or null
500
+ - {{ issue.pull_requests }} — Array of linked PRs (each has number, title, url, state, branch_name)
501
+ - {{ issue.review_decision }} — PR review decision: "approved", "changes_requested", "commented", "review_required", or null
502
+ - {{ issue.priority }} — Numeric priority or null
503
+ - {{ issue.created_at }} — ISO-8601 creation timestamp
504
+ - {{ issue.updated_at }} — ISO-8601 last-updated timestamp
505
+ - {{ issue.project }} — GitHub Projects v2 context (null for Asana):
506
+ - {{ issue.project.owner }} — Project owner login
507
+ - {{ issue.project.number }} — Project number
508
+ - {{ issue.project.project_id }} — Project GraphQL node ID (resolved at runtime)
509
+ - {{ issue.project.item_id }} — Project item GraphQL node ID
510
+ - {{ issue.project.field_id }} — Status field GraphQL node ID (resolved at runtime)
511
+ - {{ issue.project.status_options }} — Array of { name, id } for status field options
512
+ - {{ attempt }} — Retry attempt number (null on first run)
513
+ ```
514
+
515
+ ### Template Variables
516
+
517
+ The prompt template uses Liquid-compatible syntax. All `issue` fields are available:
518
+
519
+ ```markdown
520
+ {{ issue.identifier }}: {{ issue.title }}
521
+
522
+ {{ issue.description }}
523
+
524
+ State: {{ issue.state }}
525
+
526
+ {% if issue.blocked_by.size > 0 %}
527
+ Blocked by:
528
+ {% for blocker in issue.blocked_by %}
529
+ - {{ blocker.identifier }} ({{ blocker.state }})
530
+ {% endfor %}
531
+ {% endif %}
532
+
533
+ {% if issue.pull_requests.size > 0 %}
534
+ Linked pull requests:
535
+ {% for pr in issue.pull_requests %}
536
+ - PR #{{ pr.number }}: {{ pr.title }} ({{ pr.state }}){% if pr.branch_name %} — branch: {{ pr.branch_name }}{% endif %}{% if pr.url %} — {{ pr.url }}{% endif %}
537
+
538
+ {% endfor %}
539
+ {% endif %}
540
+
541
+ {% if attempt %}
542
+ Retry attempt: {{ attempt }}
543
+ {% endif %}
544
+ ```
545
+
546
+ ## CLI Usage
547
+
548
+ ```bash
549
+ # Basic usage (reads WORKFLOW.md from current directory)
550
+ agent-please
551
+
552
+ # Specify WORKFLOW.md path (positional argument)
553
+ agent-please ./WORKFLOW.md
554
+
555
+ # Enable HTTP dashboard
556
+ agent-please --port 3000
557
+
558
+ # Initialize a new GitHub Projects v2 project and scaffold WORKFLOW.md
559
+ # (Requires GITHUB_TOKEN environment variable to be set)
560
+ agent-please init --owner <org-or-user> --title "My Project"
561
+
562
+ # Alternatively, provide the token via a flag:
563
+ agent-please init --owner <org-or-user> --title "My Project" --token <your-github-token>
564
+
565
+ # Show help
566
+ agent-please --help
567
+ ```
568
+
569
+ ## GitHub App Authentication
570
+
571
+ The `github_projects` tracker supports two authentication methods:
572
+
573
+ | Method | Config fields | When to use |
574
+ |--------|--------------|-------------|
575
+ | **PAT** | `api_key` | Personal access tokens — quick setup |
576
+ | **GitHub App** | `app_id`, `private_key`, `installation_id` | Organizations — fine-grained permissions, higher rate limits |
577
+
578
+ When both are present, `api_key` (PAT) takes precedence.
579
+
580
+ ### Setting up GitHub App credentials
581
+
582
+ 1. Create a GitHub App with the following permissions:
583
+ - **Repository permissions**:
584
+ - `Contents`: Read-only
585
+ - `Issues`: Read & write
586
+ - `Pull requests`: Read & write
587
+ - **Organization permissions**:
588
+ - `Projects`: Read & write
589
+ 2. Install the app on your organization and note the **installation ID** (visible in the app's
590
+ installation settings URL).
591
+ 3. Generate a **private key** (`.pem` file) from the app's settings page.
592
+ 4. Set the environment variables:
593
+
594
+ ```bash
595
+ export GITHUB_APP_ID=12345
596
+ export GITHUB_APP_PRIVATE_KEY="$(cat /path/to/private-key.pem)"
597
+ export GITHUB_APP_INSTALLATION_ID=67890
598
+ ```
599
+
600
+ 5. Reference them in `WORKFLOW.md`:
601
+
602
+ ```yaml
603
+ tracker:
604
+ kind: github_projects
605
+ app_id: $GITHUB_APP_ID
606
+ private_key: $GITHUB_APP_PRIVATE_KEY
607
+ installation_id: $GITHUB_APP_INSTALLATION_ID
608
+ owner: your-org
609
+ project_number: 42
610
+ ```
611
+
612
+ The values can also be inlined directly (not recommended for secrets):
613
+
614
+ ```yaml
615
+ app_id: 12345
616
+ private_key: "-----BEGIN RSA PRIVATE KEY-----\n..."
617
+ installation_id: 67890
618
+ ```
619
+
620
+ ### Validation
621
+
622
+ Agent Please validates GitHub App config at startup:
623
+
624
+ | Scenario | Result |
625
+ |----------|--------|
626
+ | `api_key` set | PAT auth — app fields ignored |
627
+ | All three app fields set (`app_id`, `private_key`, `installation_id`) | App auth |
628
+ | Only some app fields set | `incomplete_github_app_config` error |
629
+ | No auth configured | `missing_tracker_api_key` error |
630
+
631
+ ## Slack Notifications
632
+
633
+ Agent Please supports Slack as a notification channel via the [Chat SDK](https://chat-sdk.dev/)
634
+ Slack adapter. When configured, you can @mention the bot in any Slack channel to get real-time
635
+ orchestrator status (running issues, retry queue, token usage).
636
+
637
+ ### Environment Variables
638
+
639
+ ```bash
640
+ SLACK_BOT_TOKEN=xoxb-... # Bot User OAuth Token
641
+ SLACK_SIGNING_SECRET=... # Signing secret for webhook verification
642
+ ```
643
+
644
+ When both environment variables are set, the Slack adapter is automatically enabled alongside any
645
+ configured tracker (GitHub Projects v2 or Asana).
646
+
647
+ ### Webhook URL
648
+
649
+ Point your Slack app's Event Subscriptions and Interactivity request URL to:
650
+
651
+ ```
652
+ https://your-domain.com/api/webhooks/slack
653
+ ```
654
+
655
+ ### Slack App Setup
656
+
657
+ 1. Go to [api.slack.com/apps](https://api.slack.com/apps) and click **Create New App** > **From an app manifest**.
658
+ 2. Select your workspace and paste the following manifest:
659
+
660
+ ```yaml
661
+ display_information:
662
+ name: Agent Please
663
+ description: Orchestrator status bot
664
+ features:
665
+ bot_user:
666
+ display_name: Agent Please
667
+ always_online: true
668
+ oauth_config:
669
+ scopes:
670
+ bot:
671
+ - app_mentions:read
672
+ - channels:history
673
+ - channels:read
674
+ - chat:write
675
+ - groups:history
676
+ - groups:read
677
+ - im:history
678
+ - im:read
679
+ - reactions:read
680
+ - reactions:write
681
+ - users:read
682
+ settings:
683
+ event_subscriptions:
684
+ request_url: https://your-domain.com/api/webhooks/slack
685
+ bot_events:
686
+ - app_mention
687
+ - message.channels
688
+ - message.groups
689
+ - message.im
690
+ interactivity:
691
+ is_enabled: true
692
+ request_url: https://your-domain.com/api/webhooks/slack
693
+ org_deploy_enabled: false
694
+ socket_mode_enabled: false
695
+ token_rotation_enabled: false
696
+ ```
697
+
698
+ 3. Replace `https://your-domain.com/api/webhooks/slack` with your deployed webhook URL.
699
+ 4. Click **Create**, then go to **Basic Information** > **App Credentials** and copy the **Signing Secret** as `SLACK_SIGNING_SECRET`.
700
+ 5. Go to **OAuth & Permissions**, click **Install to Workspace**, and copy the **Bot User OAuth Token** (`xoxb-...`) as `SLACK_BOT_TOKEN`.
701
+ 6. Invite the bot to a channel and @mention it to see the orchestrator status.
702
+
703
+ ## Trust and Safety
704
+
705
+ Agent Please runs Claude Code autonomously. Understand the trust implications before deploying.
706
+
707
+ ### Permission Modes
708
+
709
+ | Mode | Behavior | Recommended For |
710
+ |---|---|---|
711
+ | `default` | Interactive approval for sensitive operations | Development, unknown repositories |
712
+ | `acceptEdits` | Auto-approve file edits; prompt for shell commands | Trusted codebases |
713
+ | `bypassPermissions` | Auto-approve all operations | Sandboxed CI environments |
714
+
715
+ Start with `default` or `acceptEdits` unless you are running in a fully isolated environment.
716
+
717
+ ### Workspace Isolation
718
+
719
+ - Each issue runs in a dedicated directory under `workspace.root`.
720
+ - Claude Code's working directory is validated against the workspace path before launch.
721
+ - Workspace paths are sanitized to prevent path traversal attacks.
722
+
723
+ ### Recommendations
724
+
725
+ - Use `acceptEdits` permission mode as a baseline for most deployments.
726
+ - Use `bypassPermissions` only in network-isolated CI runners or Docker containers.
727
+ - Set `agent.max_concurrent_agents` conservatively when first testing.
728
+ - Monitor agent runs via the HTTP dashboard (`--port`) or structured logs.
729
+ - Keep API tokens scoped to the minimum required permissions.
730
+
731
+ ## License
732
+
733
+ Functional Source License 1.1, MIT Future License (FSL-1.1-MIT). See [LICENSE](LICENSE) for details.
734
+
735
+ ### Third-Party Licenses
736
+
737
+ - Agent Please is a TypeScript implementation based on the [Symphony specification](vendor/symphony/SPEC.md) by OpenAI (Apache 2.0).
738
+ - This project uses the [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-typescript), which is subject to Anthropic's [Commercial Terms of Service](https://www.anthropic.com/legal/commercial-terms).