Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ece0f70
feat: replace the starter agent with the coding agent sample
zimeg Oct 7, 2026
83549c8
feat: keep the OAuth entry point and the starter README structure
zimeg Oct 8, 2026
7afde43
chore: remove the maintainers guide and check dependencies daily
zimeg Oct 8, 2026
ca080d5
refactor: match the OAuth entry point to the starter template
zimeg Oct 8, 2026
2446b58
test: split the listener tests to match each listener
zimeg Oct 8, 2026
95b6c94
fix: confirm a stop and move the session out of processing
zimeg Oct 8, 2026
8d43b0d
fix: answer pending tool calls in history so stopped approvals don't …
zimeg Oct 9, 2026
a8b5a31
fix: gate commands that do more than read and keep listeners framewor…
zimeg Oct 13, 2026
fb30af3
feat: answer direct messages, edit files without approval, and run tu…
zimeg Oct 14, 2026
e654e88
Merge remote-tracking branch 'origin/main' into coding-agent
zimeg Oct 14, 2026
819370c
chore: keep the dependency merge workflow unchanged
zimeg Oct 14, 2026
f4623f7
ci: run tests on Python 3.14 only
zimeg Oct 14, 2026
f4ddcb6
refactor: keep the run_command approval hook with the other tool-call…
zimeg Oct 15, 2026
682e80e
refactor: run commands without a shell on every platform
zimeg Oct 15, 2026
fe7ebc2
refactor: keep the command environment helper private to the workspace
zimeg Oct 15, 2026
4463906
refactor: define the .git check before the path resolver that uses it
zimeg Oct 15, 2026
68751f2
refactor: define turn helpers before the functions that use them
zimeg Oct 15, 2026
71bbf73
fix: add the code channel slash command URL and update stale comments
zimeg Oct 15, 2026
72233a8
refactor: keep the run deps with the sessions they carry
zimeg Oct 16, 2026
21a03ed
fix: quiet a turn still running when its channel is archived from Slack
zimeg Oct 16, 2026
fcd490e
docs: describe where the framework lives and what turns.py relies on
zimeg Oct 16, 2026
92d2857
docs: slack code
zimeg Oct 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 0 additions & 75 deletions .claude/CLAUDE.md

This file was deleted.

35 changes: 0 additions & 35 deletions .claude/commands/unvendor-bolt.md

This file was deleted.

38 changes: 0 additions & 38 deletions .claude/commands/vendor-bolt.md

This file was deleted.

17 changes: 0 additions & 17 deletions .github/MAINTAINERS_GUIDE.md

This file was deleted.

12 changes: 8 additions & 4 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ updates:
directories:
- "/"
- "/openai-agents-sdk"
- "/pydantic-ai"
- "/claude-agent-sdk"
schedule:
interval: "weekly"
interval: "daily"
cooldown:
default-days: 7
exclude:
- "slack-*"
labels:
- "pip"
- "dependencies"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
interval: "daily"
cooldown:
default-days: 7
15 changes: 9 additions & 6 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
Expand All @@ -13,23 +16,23 @@ jobs:
matrix:
directory:
- openai-agents-sdk
- pydantic-ai
- claude-agent-sdk
defaults:
run:
working-directory: ${{ matrix.directory }}

steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
python-version: "3.14"
- name: Install dependencies
run: |
pip install -U pip
pip install -r requirements.txt
- name: Lint and check formatting with ruff
run: |
ruff check .
ruff format --check .
ruff format --check .
13 changes: 8 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -13,18 +16,18 @@ jobs:
matrix:
directory:
- openai-agents-sdk
- pydantic-ai
- claude-agent-sdk
defaults:
run:
working-directory: ${{ matrix.directory }}

steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
python-version: "3.14"
- name: Install dependencies
run: |
pip install -U pip
Expand Down
61 changes: 61 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# AGENTS.md

Guidance for coding agents working in this repository.

## What this is

A monorepo for a **Coding Agent** sample for Slack, built with Bolt for Python. Each framework lives in its own directory as a standalone sample:

- `openai-agents-sdk/` — built with the **OpenAI Agents SDK**

Implementations share a structure and user experience, not code. Keep each one obvious on its own, written in its framework's idiom, rather than adding shared helpers.

## Commands

Run these from inside an implementation directory, such as `openai-agents-sdk/`:

```sh
# Run the app (requires .env with the framework's API key; Slack tokens are optional with the CLI)
slack run # via Slack CLI
python3 app.py # directly

# Lint and format (CI runs these on push to main and all PRs)
ruff check .
ruff format --check .

# Run tests
pytest
```

## Repository structure

```
.github/ # Shared CI workflows and dependabot config
openai-agents-sdk/ # OpenAI Agents SDK implementation
```

CI runs ruff and pytest against each directory with a matrix in `.github/workflows/ruff.yml` and `.github/workflows/tests.yml`. Dependabot watches each directory separately. When adding an implementation, add its directory to both workflow matrices, to `.github/dependabot.yml`, and to the framework table in the root `README.md`.

## Architecture

Three layers: **app.py** -> **listeners/** -> **agent/**.

- **`app.py`** starts Bolt's `AsyncApp` in Socket Mode and calls `register_listeners(app)`. **`app_oauth.py`** is the alternative entry point for OAuth over HTTP, where agent slash commands arrive at the manifest's `code_channels.slash_command_url`. Everything is async, so a long turn never holds up the stop button, an approval click, or another channel.
- **`listeners/`** holds Bolt handlers only, grouped by Slack feature (`actions/`, `commands/`, `events/`). Each sub-package has a `register(app)` function.
- **`agent/`** holds everything else: the agents and their prompts, one file per tool under `agent/tools/`, the turn handling, the sessions and the deps each run gets, and command approvals.

The flow: a mention or direct message outside a code channel runs a small routing agent that either replies in place or calls `create_code_channel`. Slack seeds the new channel with the request, and that mention starts the coding agent's first turn there, along with the conversation the request came from. Every later message, slash command, and approval in the channel runs a turn of the same session. Messages sent while a turn runs wait and go into the next turn together.

## Keeping implementations alike

Implementations share structure, not code, so these parts are kept the same by copying them and changing them everywhere at once:

- **The seam between `listeners/` and `agent/`.** Listeners import only from the `agent` package, never from the agent framework, so `listeners/` is the same in every implementation. `agent/__init__.py` provides `answer_request`, `find_session`, `run_turn`, `resume_turn`, `stop_turn`, and `end_session`.
- **Framework-free files.** `agent/turns.py`, `agent/context.py`, `agent/approvals.py`, `agent/sessions.py`, `agent/workspace.py`, `agent/outcome.py`, and `agent/prompts.py` don't import the agent framework. The framework lives in `agent/agent.py`, `agent/guardrails.py`, and `agent/tools/`. `turns.py` calls only `run_request(prompt, deps)`, which returns the reply text, and `start_run(history, text, deps)` and `resume_run(paused, approved, deps)`, which return the `RunOutcome` in `agent/outcome.py`. The paused run is a handle `turns.py` passes back without looking inside, so each framework's way of pausing fits behind it.
- **What the framework side keeps true.** `turns.py` relies on these, so every implementation keeps them: `create_code_channel` sets `deps.code_channel_id`, and `archive_channel` sets `session.archived`. Every code channel tool skips its call once `session.stopped` is set. A paused run's history already records the pending command as not run, so `turns.py` can drop a paused run without resuming it. Beyond that, `turns.py` only checks whether `history` is empty, to know a turn is the first.
- **Prompts.** `agent/prompts.py` is the same word for word in every implementation.
- **Tools.** Every implementation offers the same tools with the same names, arguments, and descriptions, written with its framework's tool decorator. File tools stay inside the clone and can't write into `.git`.
- **Command approvals.** `command_needs_approval(command)` is plain Python and the same in every implementation, wrapped in the framework's own approval hook. Read-only commands and local git changes run without asking. Anything that runs the repository's code or reaches outside the clone asks first. Commands run without a shell, so the check and the run split a command the same way. On Windows, `.cmd` and `.bat` programs like `npm` are the exception, since Windows runs them through `cmd.exe`.
- **Tests.** Test files and names mirror each other, and `tests/test_runs.py` drives real agent runs with a scripted model to cover pausing, resuming, stopping, and running out of turns.

Refer to each implementation's README for its specifics.
Loading
Loading