chiefofstaff 0.1.0__tar.gz
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.
- chiefofstaff-0.1.0/.coverage +0 -0
- chiefofstaff-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +28 -0
- chiefofstaff-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- chiefofstaff-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +15 -0
- chiefofstaff-0.1.0/.github/pull_request_template.md +8 -0
- chiefofstaff-0.1.0/.github/workflows/copilot.yml +37 -0
- chiefofstaff-0.1.0/.github/workflows/release.yml +38 -0
- chiefofstaff-0.1.0/.github/workflows/test.yml +48 -0
- chiefofstaff-0.1.0/.gitignore +13 -0
- chiefofstaff-0.1.0/CHANGELOG.md +21 -0
- chiefofstaff-0.1.0/CODE_OF_CONDUCT.md +11 -0
- chiefofstaff-0.1.0/CONTRIBUTING.md +126 -0
- chiefofstaff-0.1.0/LICENSE +21 -0
- chiefofstaff-0.1.0/PKG-INFO +158 -0
- chiefofstaff-0.1.0/README.md +121 -0
- chiefofstaff-0.1.0/README.zh-CN.md +115 -0
- chiefofstaff-0.1.0/SECURITY.md +85 -0
- chiefofstaff-0.1.0/docs/ARCHITECTURE.md +153 -0
- chiefofstaff-0.1.0/docs/good-first-issues.md +25 -0
- chiefofstaff-0.1.0/docs/guide.md +245 -0
- chiefofstaff-0.1.0/docs/images/approve-dark.png +0 -0
- chiefofstaff-0.1.0/docs/images/inbox-review.png +0 -0
- chiefofstaff-0.1.0/docs/images/running.png +0 -0
- chiefofstaff-0.1.0/eslint.config.mjs +26 -0
- chiefofstaff-0.1.0/pyproject.toml +98 -0
- chiefofstaff-0.1.0/scripts/browser_smoke.py +245 -0
- chiefofstaff-0.1.0/scripts/demo_smoke.py +154 -0
- chiefofstaff-0.1.0/scripts/fake_oauth_mcp.py +190 -0
- chiefofstaff-0.1.0/scripts/fake_slack_mcp.py +294 -0
- chiefofstaff-0.1.0/scripts/live_e2e.py +947 -0
- chiefofstaff-0.1.0/slack-manifest.json +34 -0
- chiefofstaff-0.1.0/src/chiefofstaff/__init__.py +3 -0
- chiefofstaff-0.1.0/src/chiefofstaff/__main__.py +122 -0
- chiefofstaff-0.1.0/src/chiefofstaff/asks.py +560 -0
- chiefofstaff-0.1.0/src/chiefofstaff/backend.py +253 -0
- chiefofstaff-0.1.0/src/chiefofstaff/bus.py +48 -0
- chiefofstaff-0.1.0/src/chiefofstaff/catalog.py +67 -0
- chiefofstaff-0.1.0/src/chiefofstaff/delivery.py +199 -0
- chiefofstaff-0.1.0/src/chiefofstaff/demo.py +500 -0
- chiefofstaff-0.1.0/src/chiefofstaff/digest.py +68 -0
- chiefofstaff-0.1.0/src/chiefofstaff/drafts.py +262 -0
- chiefofstaff-0.1.0/src/chiefofstaff/envelope.py +70 -0
- chiefofstaff-0.1.0/src/chiefofstaff/events.py +272 -0
- chiefofstaff-0.1.0/src/chiefofstaff/focus.py +111 -0
- chiefofstaff-0.1.0/src/chiefofstaff/models.py +143 -0
- chiefofstaff-0.1.0/src/chiefofstaff/notify.py +32 -0
- chiefofstaff-0.1.0/src/chiefofstaff/policy.py +140 -0
- chiefofstaff-0.1.0/src/chiefofstaff/prompts.py +300 -0
- chiefofstaff-0.1.0/src/chiefofstaff/receipts.py +240 -0
- chiefofstaff-0.1.0/src/chiefofstaff/roles.py +3 -0
- chiefofstaff-0.1.0/src/chiefofstaff/runtime.py +1152 -0
- chiefofstaff-0.1.0/src/chiefofstaff/scripted.py +378 -0
- chiefofstaff-0.1.0/src/chiefofstaff/sources/__init__.py +39 -0
- chiefofstaff-0.1.0/src/chiefofstaff/sources/github.py +280 -0
- chiefofstaff-0.1.0/src/chiefofstaff/sources/slack.py +511 -0
- chiefofstaff-0.1.0/src/chiefofstaff/state.py +85 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/app.js +134 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/dom.js +60 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/drafts.js +221 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/inbox.js +553 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/index.html +189 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/session.js +371 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/settings.js +201 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/sidebar.js +169 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/state.js +138 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/style.css +701 -0
- chiefofstaff-0.1.0/src/chiefofstaff/static/text.js +210 -0
- chiefofstaff-0.1.0/src/chiefofstaff/store.py +552 -0
- chiefofstaff-0.1.0/src/chiefofstaff/task_actions.py +294 -0
- chiefofstaff-0.1.0/src/chiefofstaff/tasks.py +307 -0
- chiefofstaff-0.1.0/src/chiefofstaff/threads.py +64 -0
- chiefofstaff-0.1.0/src/chiefofstaff/tools.py +937 -0
- chiefofstaff-0.1.0/src/chiefofstaff/watchdog.py +188 -0
- chiefofstaff-0.1.0/src/chiefofstaff/web.py +294 -0
- chiefofstaff-0.1.0/src/chiefofstaff/workers.py +389 -0
- chiefofstaff-0.1.0/src/chiefofstaff/workspaces.py +360 -0
- chiefofstaff-0.1.0/tests/conftest.py +324 -0
- chiefofstaff-0.1.0/tests/test_asks.py +336 -0
- chiefofstaff-0.1.0/tests/test_backend_contract.py +260 -0
- chiefofstaff-0.1.0/tests/test_demo.py +74 -0
- chiefofstaff-0.1.0/tests/test_faults.py +229 -0
- chiefofstaff-0.1.0/tests/test_features.py +595 -0
- chiefofstaff-0.1.0/tests/test_github_source.py +193 -0
- chiefofstaff-0.1.0/tests/test_receipts.py +89 -0
- chiefofstaff-0.1.0/tests/test_repos.py +377 -0
- chiefofstaff-0.1.0/tests/test_runtime.py +831 -0
- chiefofstaff-0.1.0/tests/test_slack_source.py +260 -0
- chiefofstaff-0.1.0/tests/test_store.py +41 -0
- chiefofstaff-0.1.0/tests/test_tasks.py +238 -0
- chiefofstaff-0.1.0/tests/test_threads.py +310 -0
- chiefofstaff-0.1.0/tests/test_watchdog.py +56 -0
- chiefofstaff-0.1.0/tests/test_web.py +170 -0
- chiefofstaff-0.1.0/uv.lock +1145 -0
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something does not work as described.
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened, and what did you expect?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: steps
|
|
13
|
+
attributes:
|
|
14
|
+
label: How to reproduce
|
|
15
|
+
description: Ideally in demo mode (chiefofstaff --demo), so anyone can try it.
|
|
16
|
+
- type: input
|
|
17
|
+
id: versions
|
|
18
|
+
attributes:
|
|
19
|
+
label: Versions
|
|
20
|
+
description: "chiefofstaff --version, copilot --version, and your OS"
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: details
|
|
25
|
+
attributes:
|
|
26
|
+
label: Logs or the session timeline
|
|
27
|
+
description: Remove anything private (tokens, Slack messages, company code) first.
|
|
28
|
+
render: text
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: Idea
|
|
2
|
+
description: Something Chief of Staff should do.
|
|
3
|
+
labels: [idea]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What gets in your way today?
|
|
9
|
+
description: The situation, not the solution. Who interrupts you, what you have to watch.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: idea
|
|
14
|
+
attributes:
|
|
15
|
+
label: What would help?
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## What changes for the owner
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. Screenshots from the demo for UI changes. -->
|
|
4
|
+
|
|
5
|
+
## How it was tested
|
|
6
|
+
|
|
7
|
+
- [ ] `uv run ruff check . && uv run ruff format --check . && uv run pytest -q`
|
|
8
|
+
- [ ] Demo or live test, if it changes behavior: <!-- which -->
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Copilot integration
|
|
2
|
+
# The contract tests against the real GitHub Copilot CLI. They need a token with Copilot access
|
|
3
|
+
# (a fine-grained personal access token with the "Copilot Requests" permission) stored as the
|
|
4
|
+
# COPILOT_GITHUB_TOKEN secret; without it the job is skipped.
|
|
5
|
+
on:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: "17 6 * * *"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
jobs:
|
|
12
|
+
contract:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
env:
|
|
15
|
+
GH_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
|
|
16
|
+
steps:
|
|
17
|
+
- name: Skip without a Copilot token
|
|
18
|
+
id: token
|
|
19
|
+
run: echo "present=${{ secrets.COPILOT_GITHUB_TOKEN != '' }}" >> "$GITHUB_OUTPUT"
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
if: steps.token.outputs.present == 'true'
|
|
22
|
+
- uses: actions/setup-node@v4
|
|
23
|
+
if: steps.token.outputs.present == 'true'
|
|
24
|
+
with:
|
|
25
|
+
node-version: "22"
|
|
26
|
+
- uses: astral-sh/setup-uv@v6
|
|
27
|
+
if: steps.token.outputs.present == 'true'
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.13"
|
|
30
|
+
- if: steps.token.outputs.present == 'true'
|
|
31
|
+
run: npm install -g @github/copilot
|
|
32
|
+
- if: steps.token.outputs.present == 'true'
|
|
33
|
+
run: uv sync --locked --extra dev
|
|
34
|
+
- if: steps.token.outputs.present == 'true'
|
|
35
|
+
run: uv run --extra dev pytest -q -m copilot tests/test_backend_contract.py
|
|
36
|
+
env:
|
|
37
|
+
CHIEFOFSTAFF_TEST_COPILOT: "1"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
# Pushing a tag like v0.1.0 builds the package and publishes it to PyPI with trusted publishing
|
|
3
|
+
# (configure the "chiefofstaff" project on PyPI to trust this workflow first).
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: astral-sh/setup-uv@v6
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.13"
|
|
15
|
+
- run: uv sync --locked --extra dev
|
|
16
|
+
- run: uv run --locked --extra dev pytest -q
|
|
17
|
+
- run: uv build
|
|
18
|
+
- uses: actions/upload-artifact@v4
|
|
19
|
+
with:
|
|
20
|
+
name: dist
|
|
21
|
+
path: dist/
|
|
22
|
+
publish:
|
|
23
|
+
needs: build
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
environment: pypi
|
|
26
|
+
permissions:
|
|
27
|
+
id-token: write
|
|
28
|
+
contents: write
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/download-artifact@v4
|
|
31
|
+
with:
|
|
32
|
+
name: dist
|
|
33
|
+
path: dist/
|
|
34
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
35
|
+
- uses: softprops/action-gh-release@v2
|
|
36
|
+
with:
|
|
37
|
+
files: dist/*
|
|
38
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
python-version: ["3.11", "3.13"]
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: astral-sh/setup-uv@v6
|
|
14
|
+
with:
|
|
15
|
+
python-version: ${{ matrix.python-version }}
|
|
16
|
+
- run: uv sync --locked --extra dev
|
|
17
|
+
- run: uv run --locked --extra dev ruff check .
|
|
18
|
+
- run: uv run --locked --extra dev ruff format --check .
|
|
19
|
+
- run: uv run --locked --extra dev pyright
|
|
20
|
+
- run: npx --yes eslint@10.14.0 src/chiefofstaff/static
|
|
21
|
+
- run: uv run --locked --extra dev pytest -q
|
|
22
|
+
|
|
23
|
+
demo-ui:
|
|
24
|
+
# The whole product in a browser, with scripted sessions: no Copilot or Slack account.
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: astral-sh/setup-uv@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.13"
|
|
31
|
+
- run: uv sync --locked --extra dev
|
|
32
|
+
- run: uv run --with playwright python -m playwright install --with-deps chromium
|
|
33
|
+
- run: uv run --with playwright python scripts/demo_smoke.py
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
if: always()
|
|
36
|
+
with:
|
|
37
|
+
name: demo-screenshots
|
|
38
|
+
path: browser-shots/
|
|
39
|
+
|
|
40
|
+
secrets:
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v4
|
|
44
|
+
with:
|
|
45
|
+
fetch-depth: 0
|
|
46
|
+
- uses: gitleaks/gitleaks-action@v2
|
|
47
|
+
env:
|
|
48
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-11-02)
|
|
4
|
+
|
|
5
|
+
First public release.
|
|
6
|
+
|
|
7
|
+
- **Router** that splits requests into tasks, routes follow-ups to the worker that already
|
|
8
|
+
knows the subject, and asks you when it is unsure which project a task belongs to.
|
|
9
|
+
- **Tasks and runs**: dependencies, reports, retries, cancellation and usage per task.
|
|
10
|
+
- **Inbox**: what needs you, what is running, and results ready to review with **receipts**
|
|
11
|
+
(observed test runs, changes, commits and PR checks next to what the worker reported).
|
|
12
|
+
- **Focus Shield**: notifications wait while you focus; one summary afterwards.
|
|
13
|
+
- **Delegate by reaction**: react 🤖 to any Slack message to turn it into a task, answered
|
|
14
|
+
in its thread when done.
|
|
15
|
+
- **Slack and GitHub**: replies and PR reviews drafted in your voice, sent only after you
|
|
16
|
+
approve; followed threads and PRs go straight to their worker.
|
|
17
|
+
- **Watchdog** that notices stalled or looping workers and nudges them.
|
|
18
|
+
- **Sandboxed workers** (Copilot's OS sandbox): writes only to their own folders, no access to
|
|
19
|
+
your keys, GitHub credentials through a proxy.
|
|
20
|
+
- **Reliable delivery**: interrupted sends and drafts are checked before anything is resent.
|
|
21
|
+
- **Demo mode** (`chiefofstaff --demo`): the whole product without any account.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
|
|
4
|
+
In short: be kind, assume good intent, critique ideas rather than people, and make room for
|
|
5
|
+
newcomers. Harassment and personal attacks are not tolerated, in issues, pull requests,
|
|
6
|
+
discussions or anywhere the project is represented.
|
|
7
|
+
|
|
8
|
+
Report unacceptable behavior privately to the maintainers through GitHub (the
|
|
9
|
+
"Report content" option, or a private security advisory for anything sensitive). Reports are
|
|
10
|
+
handled confidentially; maintainers may remove content and block participants who break this
|
|
11
|
+
code.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping. This page gets you from a clone to a merged change. The map of the code is
|
|
4
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md); a list of well-scoped first changes is
|
|
5
|
+
[docs/good-first-issues.md](docs/good-first-issues.md).
|
|
6
|
+
|
|
7
|
+
## Set up
|
|
8
|
+
|
|
9
|
+
You need Python 3.11+ and [uv](https://docs.astral.sh/uv/). A Copilot account is optional:
|
|
10
|
+
most work needs none.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/evanl666/chiefofstaff && cd chiefofstaff
|
|
14
|
+
uv sync --extra dev
|
|
15
|
+
uv run chiefofstaff --demo # the whole product, scripted, no accounts
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Tests
|
|
19
|
+
|
|
20
|
+
| Command | What | Needs |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `uv run pytest -q` | Unit and scenario tests (fake and scripted backends) | Nothing |
|
|
23
|
+
| `uv run --with playwright python scripts/demo_smoke.py` | The UI through the demo scenario, light and dark | `playwright install chromium` once |
|
|
24
|
+
| `CHIEFOFSTAFF_TEST_COPILOT=1 uv run pytest -q -m copilot` | Contract tests against the real Copilot CLI | Copilot; a few small model calls |
|
|
25
|
+
| `uv run python scripts/live_e2e.py` | Every feature end to end with real Copilot | Copilot; ~10 minutes of model use |
|
|
26
|
+
| `uv run --with playwright python scripts/browser_smoke.py` | The UI with real Copilot | Copilot |
|
|
27
|
+
|
|
28
|
+
Before a pull request:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv run ruff check . && uv run ruff format --check . && uv run pyright && uv run pytest -q
|
|
32
|
+
npx eslint@10 src/chiefofstaff/static # the web UI
|
|
33
|
+
```
|
|
34
|
+
CI runs those, the demo browser test and a secret scan on every push.
|
|
35
|
+
|
|
36
|
+
Write tests for behavior, not for implementation: a scenario through `tests/conftest.py`'s
|
|
37
|
+
`Harness` (a fake Copilot you drive with `session.emit(...)`) is usually right. Failures at the
|
|
38
|
+
worst moment belong in `tests/test_faults.py`.
|
|
39
|
+
|
|
40
|
+
## Style
|
|
41
|
+
|
|
42
|
+
- Code: `ruff` (100 columns) and `pyright` for Python, ESLint for the UI; all clean. Names say what things are; comments say why, not what.
|
|
43
|
+
- Text the owner reads (UI, notifications, prompts): short, plain, specific. No exclamation
|
|
44
|
+
marks, no "successfully".
|
|
45
|
+
- Keep the UI simple: plain HTML, CSS and JavaScript; no framework or build step.
|
|
46
|
+
- One change per pull request, with a test. Say what changes for the owner.
|
|
47
|
+
|
|
48
|
+
## Add an event source
|
|
49
|
+
|
|
50
|
+
Teams, email, Linear, PagerDuty: a source watches something and hands new events to the
|
|
51
|
+
runtime. Slack (`sources/slack.py`) and GitHub (`sources/github.py`) are complete examples.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# src/chiefofstaff/sources/linear.py
|
|
55
|
+
import asyncio
|
|
56
|
+
|
|
57
|
+
from ..store import Store
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class LinearSource:
|
|
61
|
+
name = "linear"
|
|
62
|
+
|
|
63
|
+
def __init__(self, store: Store, host, client):
|
|
64
|
+
self.store, self.host, self.client = store, host, client
|
|
65
|
+
self.status = {"enabled": True, "connected": False, "error": ""}
|
|
66
|
+
self.job = None
|
|
67
|
+
|
|
68
|
+
async def start(self):
|
|
69
|
+
self.job = asyncio.create_task(self.loop())
|
|
70
|
+
|
|
71
|
+
async def stop(self):
|
|
72
|
+
if self.job:
|
|
73
|
+
self.job.cancel()
|
|
74
|
+
|
|
75
|
+
def wake(self):
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
async def loop(self):
|
|
79
|
+
while True:
|
|
80
|
+
for issue in await self.client.assigned_to_me():
|
|
81
|
+
# A stable key per event: the same issue update never reaches the Router twice.
|
|
82
|
+
await self.host.on_trigger(
|
|
83
|
+
"linear",
|
|
84
|
+
[f"linear:{issue.id}@{issue.updated_at}"],
|
|
85
|
+
f"New issue assigned to the owner: {issue.title}\n{issue.url}",
|
|
86
|
+
)
|
|
87
|
+
await asyncio.sleep(120)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Register it with `runtime.sources.append(LinearSource(store, runtime, client))` (in the
|
|
91
|
+
runtime factory, or behind a setting). The Router receives the event in an envelope marked
|
|
92
|
+
`trust="untrusted"`; tell it what to do with such events in `prompts.py` if the default
|
|
93
|
+
judgment is not enough. To let sessions follow an item (comments go straight to the worker),
|
|
94
|
+
add a thread key format in `threads.py` and call `host.on_thread(...)` for followed items, as
|
|
95
|
+
`GitHubSource.poll_pull` does.
|
|
96
|
+
|
|
97
|
+
## Debug a delivery
|
|
98
|
+
|
|
99
|
+
Everything a session was sent is in the database. With Chief of Staff running (WAL mode lets
|
|
100
|
+
you read it):
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
DB=~/Library/Application\ Support/chiefofstaff/chiefofstaff.db # see "Data:" at startup
|
|
104
|
+
sqlite3 "$DB" "select substr(id,1,8), role, status, title from sessions where closed_at is null"
|
|
105
|
+
# A session's timeline; rows with meta.prompt are its outbox
|
|
106
|
+
sqlite3 "$DB" "select id, kind, substr(text,1,60), substr(meta,1,80) from messages
|
|
107
|
+
where session_id like 'abcd1234%' order by id desc limit 20"
|
|
108
|
+
# How far it was sent (sent:) and handled (idle:); a sending: key means a send was interrupted
|
|
109
|
+
sqlite3 "$DB" "select key, value from kv where key glob 's*:abcd1234*' or key glob 'idle:abcd1234*'"
|
|
110
|
+
# Tasks, runs and observed commands
|
|
111
|
+
sqlite3 "$DB" "select id, status, title from tasks order by created_at desc limit 10"
|
|
112
|
+
sqlite3 "$DB" "select run_id, kind, exit_code, substr(command,1,60) from commands order by id desc limit 10"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`copilot --resume <session id>` opens the same conversation in a terminal. To see the raw
|
|
116
|
+
JSON-RPC traffic, wrap `copilot._jsonrpc.JsonRpcClient._send_message` and `_handle_message`
|
|
117
|
+
in a small script (both take one message dict).
|
|
118
|
+
|
|
119
|
+
## Pull requests
|
|
120
|
+
|
|
121
|
+
- Describe the change from the owner's side, and how you tested it (paste the demo
|
|
122
|
+
screenshots for UI changes).
|
|
123
|
+
- Keep pull requests small; open an issue first for anything that changes how sessions behave.
|
|
124
|
+
- By contributing you agree that your contribution is licensed under the MIT license.
|
|
125
|
+
|
|
126
|
+
This project follows the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 evanl666
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: chiefofstaff
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: One inbox for all your GitHub Copilot sessions: tasks and follow-ups go to the right session, Slack replies wait for your approval, and finished work waits for your review.
|
|
5
|
+
Project-URL: Homepage, https://github.com/evanl666/chiefofstaff
|
|
6
|
+
Project-URL: Issues, https://github.com/evanl666/chiefofstaff/issues
|
|
7
|
+
Author: evanl666
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai-agents,developer-tools,github-copilot,multi-agent,orchestration,slack
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: fastapi<1,>=0.115
|
|
23
|
+
Requires-Dist: github-copilot-sdk<1.1,>=1.0.28
|
|
24
|
+
Requires-Dist: httpx<1,>=0.28
|
|
25
|
+
Requires-Dist: keyring<26,>=25
|
|
26
|
+
Requires-Dist: mcp<2,>=1.24
|
|
27
|
+
Requires-Dist: platformdirs<5,>=4
|
|
28
|
+
Requires-Dist: pydantic<3,>=2.10
|
|
29
|
+
Requires-Dist: uvicorn<1,>=0.34
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: httpx<1,>=0.28; extra == 'dev'
|
|
32
|
+
Requires-Dist: pyright==1.1.414; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio<2,>=0.25; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest<10,>=8; extra == 'dev'
|
|
35
|
+
Requires-Dist: ruff<1,>=0.11; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# Chief of Staff
|
|
39
|
+
|
|
40
|
+
**English** · [简体中文](https://github.com/evanl666/chiefofstaff/blob/main/README.zh-CN.md)
|
|
41
|
+
|
|
42
|
+
One inbox for all your GitHub Copilot sessions. Tell it what you need. It gives each task to
|
|
43
|
+
its own Copilot session, sends follow-ups to the session that already has the context, drafts
|
|
44
|
+
your Slack replies, and lets you know when something is ready to review.
|
|
45
|
+
|
|
46
|
+

|
|
47
|
+
|
|
48
|
+
Try it with scripted sessions first. No account needed:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uvx chiefofstaff --demo
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Why I built this
|
|
55
|
+
|
|
56
|
+
I usually have several Copilot sessions going at once: one fixing a test, one reviewing a PR,
|
|
57
|
+
one digging through logs. Every few minutes I'd flip between terminals to see which one was
|
|
58
|
+
stuck, which one had a question, and which one had quietly finished. Slack kept pinging me in
|
|
59
|
+
between. After a while I couldn't remember which session knew what, and I'd start a new one for
|
|
60
|
+
a follow-up that an old one could have answered in a minute.
|
|
61
|
+
|
|
62
|
+
Now I talk to one session, the Router, and Chief of Staff keeps track of the rest.
|
|
63
|
+
|
|
64
|
+
## What it does
|
|
65
|
+
|
|
66
|
+
- Splits a request into tasks. "Fix the flaky login test, then add rate limiting, and compare
|
|
67
|
+
feature-flag services" becomes three tasks. The second waits for the first and starts with
|
|
68
|
+
its result.
|
|
69
|
+
- Sends follow-ups to the session that did the work, with its history and checkout, instead of
|
|
70
|
+
starting over in a new one.
|
|
71
|
+
- Shows what was observed next to what the worker reports: the test runs, commits, diff and PR
|
|
72
|
+
checks. If a report says "all tests pass" and no test ran, the card says so.
|
|
73
|
+
- Leaves your own checkout alone. Each worker gets its own folder and git worktree and runs in
|
|
74
|
+
Copilot's OS sandbox, so it can't write anywhere else.
|
|
75
|
+
- Drafts replies to Slack DMs and mentions in your style. Nothing is sent until you press Send.
|
|
76
|
+
- Lets you delegate from Slack: react 🤖 to any message ("can someone look at the export
|
|
77
|
+
bug?") and it becomes a task. When it's done, the answer is drafted in that thread.
|
|
78
|
+
- Has a focus mode. Pick how long: notifications wait, the Router handles what it can, and you
|
|
79
|
+
get one summary at the end.
|
|
80
|
+
- Watches for workers that stall or go in circles, and nudges them.
|
|
81
|
+
|
|
82
|
+
It runs on the Copilot you already have: your plan, your models, your MCP servers and your
|
|
83
|
+
company's policies. No other AI service or API key.
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
87
|
+
## Install
|
|
88
|
+
|
|
89
|
+
You need macOS or Linux, Python 3.11 or newer, [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
|
90
|
+
(or pipx), and the [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install -g @github/copilot
|
|
94
|
+
copilot login
|
|
95
|
+
uvx chiefofstaff # or: pipx install chiefofstaff && chiefofstaff
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Your browser opens `http://127.0.0.1:8765`. Add a project folder, then type what you need in
|
|
99
|
+
the box at the bottom.
|
|
100
|
+
|
|
101
|
+
Everything runs on your machine, and your data stays in `~/Library/Application Support/chiefofstaff`
|
|
102
|
+
(macOS) or `~/.local/share/chiefofstaff` (Linux). Closing the tab doesn't stop anything; press
|
|
103
|
+
Ctrl+C in the terminal to stop. Sessions continue where they left off when you start it again.
|
|
104
|
+
|
|
105
|
+
Options: `--port`, `--data-dir`, `--no-browser`, `--demo`. To update: `uvx chiefofstaff@latest`
|
|
106
|
+
or `pipx upgrade chiefofstaff`.
|
|
107
|
+
|
|
108
|
+
## Signing in
|
|
109
|
+
|
|
110
|
+
There are a few separate sign-ins. Only the first one is required.
|
|
111
|
+
|
|
112
|
+
1. **Copilot.** Run `copilot login` once. If you haven't, the page tells you what to do. On a
|
|
113
|
+
company plan, an admin may need to turn on Copilot CLI for you.
|
|
114
|
+
2. **The page itself.** Every start prints a private link with a fresh token in the terminal
|
|
115
|
+
and opens it for you. It stays signed in for 24 hours. After a restart, use the new link.
|
|
116
|
+
Keep it to yourself: whoever has it can act as you.
|
|
117
|
+
3. **GitHub**, to review PRs you're asked to review: `gh auth login`. With the sandbox on, also
|
|
118
|
+
run `copilot sandbox ca create && copilot sandbox ca trust` once, so `gh` works inside it.
|
|
119
|
+
4. **Slack and other services.** Paste a Slack user token in Settings
|
|
120
|
+
([how to get one](https://github.com/evanl666/chiefofstaff/blob/main/docs/guide.md#slack)).
|
|
121
|
+
When a worker needs another service, like your docs or issue tracker, a sign-in card shows
|
|
122
|
+
up in the inbox.
|
|
123
|
+
|
|
124
|
+
## How it works
|
|
125
|
+
|
|
126
|
+
Every session is a regular Copilot CLI session. You'll find them in `copilot --resume`, named
|
|
127
|
+
"Chief of Staff · …". Chief of Staff drives them through the Copilot SDK:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
you ── inbox ── Router ── tasks ──► worker · worker · worker
|
|
131
|
+
▲ (own folder, worktree, sandbox)
|
|
132
|
+
Slack, GitHub ────┘ Slack session ──► drafts you approve
|
|
133
|
+
Watchdog ──► nudges stuck workers
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Sessions never talk to each other directly. They call tools like `spawn_worker`, `report` or
|
|
137
|
+
`ask_session`, and Chief of Staff delivers the message. Each message is saved before it's sent
|
|
138
|
+
and labeled with who it's from, so a Slack message can't pass itself off as you.
|
|
139
|
+
|
|
140
|
+
- [User guide](https://github.com/evanl666/chiefofstaff/blob/main/docs/guide.md)
|
|
141
|
+
- [Architecture](https://github.com/evanl666/chiefofstaff/blob/main/docs/ARCHITECTURE.md)
|
|
142
|
+
- [Security](https://github.com/evanl666/chiefofstaff/blob/main/SECURITY.md): what the OS
|
|
143
|
+
sandbox enforces, what Chief of Staff enforces, and what relies on the model following
|
|
144
|
+
instructions.
|
|
145
|
+
|
|
146
|
+
## Status
|
|
147
|
+
|
|
148
|
+
Early (0.1). Expect rough edges. Copilot usage counts against your plan like any other
|
|
149
|
+
session, and the inbox shows the credits each task used.
|
|
150
|
+
|
|
151
|
+
Bug reports and ideas are welcome as issues. If you'd like to contribute, start with
|
|
152
|
+
[CONTRIBUTING.md](https://github.com/evanl666/chiefofstaff/blob/main/CONTRIBUTING.md) and the
|
|
153
|
+
[good first issues](https://github.com/evanl666/chiefofstaff/blob/main/docs/good-first-issues.md).
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT. Chief of Staff is an independent project, not made by or affiliated with GitHub. GitHub
|
|
158
|
+
Copilot is a trademark of GitHub, Inc.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Chief of Staff
|
|
2
|
+
|
|
3
|
+
**English** · [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
One inbox for all your GitHub Copilot sessions. Tell it what you need. It gives each task to
|
|
6
|
+
its own Copilot session, sends follow-ups to the session that already has the context, drafts
|
|
7
|
+
your Slack replies, and lets you know when something is ready to review.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
Try it with scripted sessions first. No account needed:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uvx chiefofstaff --demo
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Why I built this
|
|
18
|
+
|
|
19
|
+
I usually have several Copilot sessions going at once: one fixing a test, one reviewing a PR,
|
|
20
|
+
one digging through logs. Every few minutes I'd flip between terminals to see which one was
|
|
21
|
+
stuck, which one had a question, and which one had quietly finished. Slack kept pinging me in
|
|
22
|
+
between. After a while I couldn't remember which session knew what, and I'd start a new one for
|
|
23
|
+
a follow-up that an old one could have answered in a minute.
|
|
24
|
+
|
|
25
|
+
Now I talk to one session, the Router, and Chief of Staff keeps track of the rest.
|
|
26
|
+
|
|
27
|
+
## What it does
|
|
28
|
+
|
|
29
|
+
- Splits a request into tasks. "Fix the flaky login test, then add rate limiting, and compare
|
|
30
|
+
feature-flag services" becomes three tasks. The second waits for the first and starts with
|
|
31
|
+
its result.
|
|
32
|
+
- Sends follow-ups to the session that did the work, with its history and checkout, instead of
|
|
33
|
+
starting over in a new one.
|
|
34
|
+
- Shows what was observed next to what the worker reports: the test runs, commits, diff and PR
|
|
35
|
+
checks. If a report says "all tests pass" and no test ran, the card says so.
|
|
36
|
+
- Leaves your own checkout alone. Each worker gets its own folder and git worktree and runs in
|
|
37
|
+
Copilot's OS sandbox, so it can't write anywhere else.
|
|
38
|
+
- Drafts replies to Slack DMs and mentions in your style. Nothing is sent until you press Send.
|
|
39
|
+
- Lets you delegate from Slack: react 🤖 to any message ("can someone look at the export
|
|
40
|
+
bug?") and it becomes a task. When it's done, the answer is drafted in that thread.
|
|
41
|
+
- Has a focus mode. Pick how long: notifications wait, the Router handles what it can, and you
|
|
42
|
+
get one summary at the end.
|
|
43
|
+
- Watches for workers that stall or go in circles, and nudges them.
|
|
44
|
+
|
|
45
|
+
It runs on the Copilot you already have: your plan, your models, your MCP servers and your
|
|
46
|
+
company's policies. No other AI service or API key.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
You need macOS or Linux, Python 3.11 or newer, [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
|
53
|
+
(or pipx), and the [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install -g @github/copilot
|
|
57
|
+
copilot login
|
|
58
|
+
uvx chiefofstaff # or: pipx install chiefofstaff && chiefofstaff
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Your browser opens `http://127.0.0.1:8765`. Add a project folder, then type what you need in
|
|
62
|
+
the box at the bottom.
|
|
63
|
+
|
|
64
|
+
Everything runs on your machine, and your data stays in `~/Library/Application Support/chiefofstaff`
|
|
65
|
+
(macOS) or `~/.local/share/chiefofstaff` (Linux). Closing the tab doesn't stop anything; press
|
|
66
|
+
Ctrl+C in the terminal to stop. Sessions continue where they left off when you start it again.
|
|
67
|
+
|
|
68
|
+
Options: `--port`, `--data-dir`, `--no-browser`, `--demo`. To update: `uvx chiefofstaff@latest`
|
|
69
|
+
or `pipx upgrade chiefofstaff`.
|
|
70
|
+
|
|
71
|
+
## Signing in
|
|
72
|
+
|
|
73
|
+
There are a few separate sign-ins. Only the first one is required.
|
|
74
|
+
|
|
75
|
+
1. **Copilot.** Run `copilot login` once. If you haven't, the page tells you what to do. On a
|
|
76
|
+
company plan, an admin may need to turn on Copilot CLI for you.
|
|
77
|
+
2. **The page itself.** Every start prints a private link with a fresh token in the terminal
|
|
78
|
+
and opens it for you. It stays signed in for 24 hours. After a restart, use the new link.
|
|
79
|
+
Keep it to yourself: whoever has it can act as you.
|
|
80
|
+
3. **GitHub**, to review PRs you're asked to review: `gh auth login`. With the sandbox on, also
|
|
81
|
+
run `copilot sandbox ca create && copilot sandbox ca trust` once, so `gh` works inside it.
|
|
82
|
+
4. **Slack and other services.** Paste a Slack user token in Settings
|
|
83
|
+
([how to get one](docs/guide.md#slack)).
|
|
84
|
+
When a worker needs another service, like your docs or issue tracker, a sign-in card shows
|
|
85
|
+
up in the inbox.
|
|
86
|
+
|
|
87
|
+
## How it works
|
|
88
|
+
|
|
89
|
+
Every session is a regular Copilot CLI session. You'll find them in `copilot --resume`, named
|
|
90
|
+
"Chief of Staff · …". Chief of Staff drives them through the Copilot SDK:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
you ── inbox ── Router ── tasks ──► worker · worker · worker
|
|
94
|
+
▲ (own folder, worktree, sandbox)
|
|
95
|
+
Slack, GitHub ────┘ Slack session ──► drafts you approve
|
|
96
|
+
Watchdog ──► nudges stuck workers
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Sessions never talk to each other directly. They call tools like `spawn_worker`, `report` or
|
|
100
|
+
`ask_session`, and Chief of Staff delivers the message. Each message is saved before it's sent
|
|
101
|
+
and labeled with who it's from, so a Slack message can't pass itself off as you.
|
|
102
|
+
|
|
103
|
+
- [User guide](docs/guide.md)
|
|
104
|
+
- [Architecture](docs/ARCHITECTURE.md)
|
|
105
|
+
- [Security](SECURITY.md): what the OS
|
|
106
|
+
sandbox enforces, what Chief of Staff enforces, and what relies on the model following
|
|
107
|
+
instructions.
|
|
108
|
+
|
|
109
|
+
## Status
|
|
110
|
+
|
|
111
|
+
Early (0.1). Expect rough edges. Copilot usage counts against your plan like any other
|
|
112
|
+
session, and the inbox shows the credits each task used.
|
|
113
|
+
|
|
114
|
+
Bug reports and ideas are welcome as issues. If you'd like to contribute, start with
|
|
115
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) and the
|
|
116
|
+
[good first issues](docs/good-first-issues.md).
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT. Chief of Staff is an independent project, not made by or affiliated with GitHub. GitHub
|
|
121
|
+
Copilot is a trademark of GitHub, Inc.
|