sys-buddy 1.2.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.
- sys_buddy-1.2.0/.dockerignore +37 -0
- sys_buddy-1.2.0/.env.example +12 -0
- sys_buddy-1.2.0/.github/CODEOWNERS +6 -0
- sys_buddy-1.2.0/.github/pull_request_template.md +11 -0
- sys_buddy-1.2.0/.github/workflows/ci.yml +46 -0
- sys_buddy-1.2.0/.github/workflows/pr-title.yml +38 -0
- sys_buddy-1.2.0/.github/workflows/release-please.yml +79 -0
- sys_buddy-1.2.0/.gitignore +39 -0
- sys_buddy-1.2.0/.mcp.json +8 -0
- sys_buddy-1.2.0/.release-please-manifest.json +3 -0
- sys_buddy-1.2.0/CHANGELOG.md +166 -0
- sys_buddy-1.2.0/CLAUDE.md +37 -0
- sys_buddy-1.2.0/CONTRIBUTING.md +220 -0
- sys_buddy-1.2.0/DECISIONS.md +122 -0
- sys_buddy-1.2.0/DOGFOOD.md +68 -0
- sys_buddy-1.2.0/Dockerfile +38 -0
- sys_buddy-1.2.0/KICKOFF.md +69 -0
- sys_buddy-1.2.0/LICENSE +21 -0
- sys_buddy-1.2.0/Makefile +67 -0
- sys_buddy-1.2.0/OSS.md +67 -0
- sys_buddy-1.2.0/PKG-INFO +250 -0
- sys_buddy-1.2.0/README.md +240 -0
- sys_buddy-1.2.0/SPEC.md +539 -0
- sys_buddy-1.2.0/design/NOTE.md +24 -0
- sys_buddy-1.2.0/design/README.md +22 -0
- sys_buddy-1.2.0/design/project/.thumbnail +0 -0
- sys_buddy-1.2.0/design/project/Sys-Buddy Dashboard.dc.html +839 -0
- sys_buddy-1.2.0/design/project/support.js +1768 -0
- sys_buddy-1.2.0/docker-compose.yml +24 -0
- sys_buddy-1.2.0/features/v1.1.0/README.md +264 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/01-task-list-rollup-light.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/02-todo-task-panel-light.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/03-todo-task-list-light.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/04-todo-detail-host-drop-light.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/05-todo-task-dark.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/06-todo-contract-mini-stepper-dark.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/07-listening-presence-dark.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/screens/08-no-todo-task-unchanged-light.png +0 -0
- sys_buddy-1.2.0/features/v1.1.0/seed_demo.py +147 -0
- sys_buddy-1.2.0/pyproject.toml +31 -0
- sys_buddy-1.2.0/reference/AGENT_BUS_GUIDE.md +221 -0
- sys_buddy-1.2.0/reference/NOTE.md +34 -0
- sys_buddy-1.2.0/reference/SETUP.md +58 -0
- sys_buddy-1.2.0/reference/agent_bus.py +136 -0
- sys_buddy-1.2.0/release-please-config.json +22 -0
- sys_buddy-1.2.0/releases/v1.0.0.md +38 -0
- sys_buddy-1.2.0/releases/v1.0.1.md +23 -0
- sys_buddy-1.2.0/releases/v1.1.0.md +145 -0
- sys_buddy-1.2.0/releases/v1.1.1.md +40 -0
- sys_buddy-1.2.0/sessions/2026-07-16-sys-buddy-build.md +49 -0
- sys_buddy-1.2.0/sessions/2026-07-17-sys-buddy-build.md +50 -0
- sys_buddy-1.2.0/sessions/2026-07-18-gui-mvp.md +43 -0
- sys_buddy-1.2.0/sessions/2026-07-18-security-hardening.md +56 -0
- sys_buddy-1.2.0/sessions/2026-07-19-collab-and-role-redesign.md +59 -0
- sys_buddy-1.2.0/sessions/2026-07-19-role-prompt-redesign.md +83 -0
- sys_buddy-1.2.0/sessions/2026-07-20-browser-buddy-join-page.md +89 -0
- sys_buddy-1.2.0/sessions/2026-07-20-preflight-stepper-negotiations.md +104 -0
- sys_buddy-1.2.0/sessions/2026-07-20-repair-safe-mcp-and-loader-page.md +82 -0
- sys_buddy-1.2.0/sessions/2026-07-23-get-contract-shows-proposal.md +79 -0
- sys_buddy-1.2.0/sessions/role-prompt-redesign-checklist.md +94 -0
- sys_buddy-1.2.0/src/sys_buddy/__init__.py +22 -0
- sys_buddy-1.2.0/src/sys_buddy/admin.py +358 -0
- sys_buddy-1.2.0/src/sys_buddy/api.py +844 -0
- sys_buddy-1.2.0/src/sys_buddy/audit.py +34 -0
- sys_buddy-1.2.0/src/sys_buddy/cli.py +419 -0
- sys_buddy-1.2.0/src/sys_buddy/config.py +68 -0
- sys_buddy-1.2.0/src/sys_buddy/contracts.py +200 -0
- sys_buddy-1.2.0/src/sys_buddy/db.py +310 -0
- sys_buddy-1.2.0/src/sys_buddy/gui.py +270 -0
- sys_buddy-1.2.0/src/sys_buddy/gui_app.html +1389 -0
- sys_buddy-1.2.0/src/sys_buddy/http_middleware.py +94 -0
- sys_buddy-1.2.0/src/sys_buddy/identity.py +115 -0
- sys_buddy-1.2.0/src/sys_buddy/join.html +456 -0
- sys_buddy-1.2.0/src/sys_buddy/middleware.py +137 -0
- sys_buddy-1.2.0/src/sys_buddy/onboarding.py +509 -0
- sys_buddy-1.2.0/src/sys_buddy/pairing.py +293 -0
- sys_buddy-1.2.0/src/sys_buddy/readiness.py +302 -0
- sys_buddy-1.2.0/src/sys_buddy/rules.py +107 -0
- sys_buddy-1.2.0/src/sys_buddy/server.py +61 -0
- sys_buddy-1.2.0/src/sys_buddy/service.py +467 -0
- sys_buddy-1.2.0/src/sys_buddy/slack.py +55 -0
- sys_buddy-1.2.0/src/sys_buddy/state.py +1364 -0
- sys_buddy-1.2.0/src/sys_buddy/todos.py +730 -0
- sys_buddy-1.2.0/src/sys_buddy/tools.py +722 -0
- sys_buddy-1.2.0/src/sys_buddy/ui.html +1346 -0
- sys_buddy-1.2.0/src/sys_buddy/updates.py +110 -0
- sys_buddy-1.2.0/tests/conftest.py +56 -0
- sys_buddy-1.2.0/tests/test_admin.py +64 -0
- sys_buddy-1.2.0/tests/test_api.py +524 -0
- sys_buddy-1.2.0/tests/test_cli.py +64 -0
- sys_buddy-1.2.0/tests/test_contracts.py +206 -0
- sys_buddy-1.2.0/tests/test_debug.py +88 -0
- sys_buddy-1.2.0/tests/test_directed.py +67 -0
- sys_buddy-1.2.0/tests/test_identity.py +95 -0
- sys_buddy-1.2.0/tests/test_messaging.py +233 -0
- sys_buddy-1.2.0/tests/test_onboarding.py +547 -0
- sys_buddy-1.2.0/tests/test_pairing.py +336 -0
- sys_buddy-1.2.0/tests/test_presence.py +253 -0
- sys_buddy-1.2.0/tests/test_readiness.py +182 -0
- sys_buddy-1.2.0/tests/test_security_hardening.py +540 -0
- sys_buddy-1.2.0/tests/test_server.py +47 -0
- sys_buddy-1.2.0/tests/test_slack.py +69 -0
- sys_buddy-1.2.0/tests/test_state.py +686 -0
- sys_buddy-1.2.0/tests/test_todos_api.py +442 -0
- sys_buddy-1.2.0/tests/test_todos_cli.py +259 -0
- sys_buddy-1.2.0/tests/test_todos_state.py +569 -0
- sys_buddy-1.2.0/tests/test_todos_tools.py +194 -0
- sys_buddy-1.2.0/tests/test_updates.py +101 -0
- sys_buddy-1.2.0/tests/test_version.py +33 -0
- sys_buddy-1.2.0/uv.lock +1732 -0
- sys_buddy-1.2.0/v2.md +526 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.git
|
|
2
|
+
.github
|
|
3
|
+
.venv
|
|
4
|
+
__pycache__
|
|
5
|
+
*.pyc
|
|
6
|
+
.pytest_cache
|
|
7
|
+
*.egg-info
|
|
8
|
+
.DS_Store
|
|
9
|
+
|
|
10
|
+
# runtime db (mounted via volume, not baked into the image)
|
|
11
|
+
*.db
|
|
12
|
+
*.db-wal
|
|
13
|
+
*.db-shm
|
|
14
|
+
|
|
15
|
+
# dev/editor
|
|
16
|
+
.vscode
|
|
17
|
+
.idea
|
|
18
|
+
.claude
|
|
19
|
+
|
|
20
|
+
# docs & non-runtime project material
|
|
21
|
+
sessions
|
|
22
|
+
design
|
|
23
|
+
reference
|
|
24
|
+
CONTRIBUTING.md
|
|
25
|
+
DOGFOOD.md
|
|
26
|
+
DECISIONS.md
|
|
27
|
+
KICKOFF.md
|
|
28
|
+
SPEC.md
|
|
29
|
+
v2.md
|
|
30
|
+
|
|
31
|
+
# already produced by CI, not needed to build the image
|
|
32
|
+
tests
|
|
33
|
+
docker-compose.yml
|
|
34
|
+
Dockerfile
|
|
35
|
+
.dockerignore
|
|
36
|
+
.env
|
|
37
|
+
.env.example
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Copy to .env and fill in for `docker compose up`. All are optional for local testing.
|
|
2
|
+
|
|
3
|
+
# Public https origin (e.g. your tunnel) used to build pairing/invite links.
|
|
4
|
+
# Required for a real "serve" deployment — remote mode enforces auth over it.
|
|
5
|
+
SYS_BUDDY_PUBLIC_URL=
|
|
6
|
+
|
|
7
|
+
# Agent-token lifetime in seconds. Defaults to no expiry, or 24h once
|
|
8
|
+
# SYS_BUDDY_PUBLIC_URL is set.
|
|
9
|
+
SYS_BUDDY_TOKEN_TTL=
|
|
10
|
+
|
|
11
|
+
# Optional Slack webhook for broker notifications.
|
|
12
|
+
SLACK_WEBHOOK_URL=
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Code owners for sys-buddy.
|
|
2
|
+
# Every pull request touching these paths requires review from an owner listed
|
|
3
|
+
# here before it can be merged. The catch-all below makes @tooney92 the required
|
|
4
|
+
# reviewer for ALL changes — combined with branch protection on `main`, nothing
|
|
5
|
+
# reaches main without the owner's approval.
|
|
6
|
+
* @tooney92
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- Thanks for contributing to sys-buddy! Fill this in so the owner can review quickly. -->
|
|
2
|
+
|
|
3
|
+
## What & why
|
|
4
|
+
<!-- What does this PR change, and what problem does it solve? -->
|
|
5
|
+
|
|
6
|
+
## How it was tested
|
|
7
|
+
<!-- e.g. `uv run pytest -q` output; any manual/Playwright checks against the local broker -->
|
|
8
|
+
- [ ] `uv run pytest -q` passes locally
|
|
9
|
+
|
|
10
|
+
## Notes for the reviewer
|
|
11
|
+
<!-- Anything the maintainer should look at closely, trade-offs, follow-ups. -->
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Runs on every PR and on pushes to main. Making these checks *required* in branch
|
|
4
|
+
# protection is what turns them from advisory into a merge gate — see the PR that adds
|
|
5
|
+
# this file for the one-time settings step.
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: pytest
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.11"
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: uv sync --frozen
|
|
22
|
+
- name: Run the suite
|
|
23
|
+
run: uv run pytest -q
|
|
24
|
+
|
|
25
|
+
version-guard:
|
|
26
|
+
name: version not hand-edited
|
|
27
|
+
# Only on PRs, and skip release-please's own release PR — that one legitimately
|
|
28
|
+
# bumps the version. Everyone else must leave the version to the release pipeline.
|
|
29
|
+
if: github.event_name == 'pull_request' && !startsWith(github.head_ref, 'release-please')
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 0
|
|
35
|
+
- name: Fail if the version was bumped by hand
|
|
36
|
+
run: |
|
|
37
|
+
base="origin/${{ github.base_ref }}"
|
|
38
|
+
if git diff "$base"...HEAD -- pyproject.toml | grep -qE '^\+[[:space:]]*version[[:space:]]*='; then
|
|
39
|
+
echo "::error::Don't bump the version in a PR — releases are automated (see CONTRIBUTING.md §8). Remove the pyproject.toml version change; the release bot sets it."
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
if git diff "$base"...HEAD -- src/sys_buddy/__init__.py | grep -qE '^\+.*__version__[[:space:]]*='; then
|
|
43
|
+
echo "::error::Don't set __version__ by hand — it derives from the package metadata."
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
echo "OK — no manual version edit."
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: PR Title
|
|
2
|
+
|
|
3
|
+
# We squash-merge, so the PR TITLE becomes the commit on main — and release-please
|
|
4
|
+
# reads those commits to compute the version and changelog. This check refuses a PR
|
|
5
|
+
# whose title isn't a valid Conventional Commit, so the release machinery never sees
|
|
6
|
+
# a malformed message. See CONTRIBUTING.md §8 for the types.
|
|
7
|
+
on:
|
|
8
|
+
pull_request:
|
|
9
|
+
types: [opened, edited, synchronize, reopened]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
pull-requests: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
lint-title:
|
|
16
|
+
name: conventional PR title
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: amannn/action-semantic-pull-request@v5
|
|
20
|
+
env:
|
|
21
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
+
with:
|
|
23
|
+
# Must match the type→bump table in CONTRIBUTING.md §8.
|
|
24
|
+
types: |
|
|
25
|
+
feat
|
|
26
|
+
fix
|
|
27
|
+
docs
|
|
28
|
+
chore
|
|
29
|
+
refactor
|
|
30
|
+
test
|
|
31
|
+
ci
|
|
32
|
+
# Subject after the "type:" — just require it to be non-empty and not
|
|
33
|
+
# Sentence-cased-into-a-Title, keeping titles terse and imperative.
|
|
34
|
+
requireScope: false
|
|
35
|
+
subjectPattern: ^(?![A-Z]).+$
|
|
36
|
+
subjectPatternError: |
|
|
37
|
+
The subject after "type:" should start lower-case and be a short
|
|
38
|
+
imperative summary, e.g. "feat: add docker packaging".
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# One workflow, three jobs. release-please keeps a Release PR open, auto-versioned from
|
|
4
|
+
# Conventional-Commit history; merging that PR cuts a GitHub release + tag. The publish
|
|
5
|
+
# jobs run in the SAME workflow, gated on `release_created`, rather than in a separate
|
|
6
|
+
# workflow triggered by the release event — a release created with the built-in
|
|
7
|
+
# GITHUB_TOKEN does not trigger other workflows, so chaining here is what makes publish
|
|
8
|
+
# actually fire.
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
pull-requests: write
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
release-please:
|
|
19
|
+
name: release PR / tag
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
outputs:
|
|
22
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
23
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
24
|
+
version: ${{ steps.release.outputs.version }}
|
|
25
|
+
steps:
|
|
26
|
+
- uses: googleapis/release-please-action@v4
|
|
27
|
+
id: release
|
|
28
|
+
with:
|
|
29
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
+
config-file: release-please-config.json
|
|
31
|
+
manifest-file: .release-please-manifest.json
|
|
32
|
+
|
|
33
|
+
publish-pypi:
|
|
34
|
+
name: publish to PyPI
|
|
35
|
+
needs: release-please
|
|
36
|
+
if: ${{ needs.release-please.outputs.release_created }}
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
permissions:
|
|
39
|
+
contents: read
|
|
40
|
+
id-token: write # OIDC for PyPI Trusted Publishing — no stored token/secret
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
with:
|
|
44
|
+
ref: ${{ needs.release-please.outputs.tag_name }}
|
|
45
|
+
- uses: astral-sh/setup-uv@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.11"
|
|
48
|
+
- name: Build sdist + wheel
|
|
49
|
+
run: uv build
|
|
50
|
+
- name: Publish to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
52
|
+
# No password: — Trusted Publishing authenticates via the OIDC token above.
|
|
53
|
+
|
|
54
|
+
publish-docker:
|
|
55
|
+
name: publish image to ghcr.io
|
|
56
|
+
needs: release-please
|
|
57
|
+
if: ${{ needs.release-please.outputs.release_created }}
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
permissions:
|
|
60
|
+
contents: read
|
|
61
|
+
packages: write # push to ghcr.io — uses the built-in token, no account needed
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
with:
|
|
65
|
+
ref: ${{ needs.release-please.outputs.tag_name }}
|
|
66
|
+
- name: Log in to ghcr.io
|
|
67
|
+
uses: docker/login-action@v3
|
|
68
|
+
with:
|
|
69
|
+
registry: ghcr.io
|
|
70
|
+
username: ${{ github.actor }}
|
|
71
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
72
|
+
- name: Build and push
|
|
73
|
+
uses: docker/build-push-action@v6
|
|
74
|
+
with:
|
|
75
|
+
context: .
|
|
76
|
+
push: true
|
|
77
|
+
tags: |
|
|
78
|
+
ghcr.io/${{ github.repository }}:${{ needs.release-please.outputs.version }}
|
|
79
|
+
ghcr.io/${{ github.repository }}:latest
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# OS
|
|
2
|
+
.DS_Store
|
|
3
|
+
Thumbs.db
|
|
4
|
+
|
|
5
|
+
# Editor
|
|
6
|
+
.vscode/
|
|
7
|
+
.idea/
|
|
8
|
+
*.swp
|
|
9
|
+
|
|
10
|
+
# Logs
|
|
11
|
+
*.log
|
|
12
|
+
|
|
13
|
+
# Environment
|
|
14
|
+
.env
|
|
15
|
+
.env.local
|
|
16
|
+
.env.*.local
|
|
17
|
+
|
|
18
|
+
# Dependencies / build (add stack-specific entries as the project grows)
|
|
19
|
+
node_modules/
|
|
20
|
+
dist/
|
|
21
|
+
build/
|
|
22
|
+
|
|
23
|
+
# Claude Code — local per-user settings (approvals, allowlist). .mcp.json IS tracked.
|
|
24
|
+
.claude/settings.local.json
|
|
25
|
+
|
|
26
|
+
# Python
|
|
27
|
+
.venv/
|
|
28
|
+
__pycache__/
|
|
29
|
+
*.py[cod]
|
|
30
|
+
*.egg-info/
|
|
31
|
+
.pytest_cache/
|
|
32
|
+
|
|
33
|
+
# sys-buddy runtime database
|
|
34
|
+
*.db
|
|
35
|
+
*.db-wal
|
|
36
|
+
*.db-shm
|
|
37
|
+
|
|
38
|
+
# Playwright MCP scratch output (screenshots/snapshots from browser-driven checks)
|
|
39
|
+
.playwright-mcp/
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **sys-buddy** are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/) — `MAJOR.MINOR.PATCH`:
|
|
6
|
+
|
|
7
|
+
- **MAJOR** — incompatible changes to the tool/wire contract or agent-visible behavior.
|
|
8
|
+
- **MINOR** — new, backwards-compatible capability.
|
|
9
|
+
- **PATCH** — backwards-compatible fixes.
|
|
10
|
+
|
|
11
|
+
Each release is also git-tagged `vX.Y.Z` and has a fuller note in `releases/vX.Y.Z.md`.
|
|
12
|
+
|
|
13
|
+
## [1.2.0](https://github.com/tooney92/sys-buddy/compare/v1.1.1...v1.2.0) (2026-07-25)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
* version awareness — /api/version, single-sourced version, GUI banner ([2506b8a](https://github.com/tooney92/sys-buddy/commit/2506b8a26a107061585600ac7a116d0ffd87f3b7))
|
|
19
|
+
* version awareness (/api/version + GUI update banner) ([4e23c5b](https://github.com/tooney92/sys-buddy/commit/4e23c5b1eaa5b94cd5bab07414719e22368ffec9))
|
|
20
|
+
|
|
21
|
+
## [Unreleased]
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **Version awareness in the desktop app.** A new unauthenticated `GET /api/version`
|
|
25
|
+
reports the version the broker process is actually *running*. The desktop app compares
|
|
26
|
+
three numbers — installed (on disk), running (from the endpoint), and, if the user opts
|
|
27
|
+
in, the latest published GitHub release — and shows a banner when they disagree: a
|
|
28
|
+
"restart needed" warning when the broker is serving older code than what's installed
|
|
29
|
+
(the drift that hid a migration in 1.1.0/1.1.1), or an "update available" note with the
|
|
30
|
+
release notes inline when GitHub has something newer. The GitHub check is strictly
|
|
31
|
+
opt-in — the app makes no external request unless the toggle is on.
|
|
32
|
+
- **Version is single-sourced.** `sys_buddy.__version__` now derives from the installed
|
|
33
|
+
package metadata rather than a second hand-edited literal, so `pyproject.toml` is the
|
|
34
|
+
one place to bump it; a test fails the build if the two ever drift.
|
|
35
|
+
- **Docker packaging.** A multi-stage root `Dockerfile` (built with `uv`) and
|
|
36
|
+
`docker-compose.yml` run the broker as a single container, non-root, with a persisted
|
|
37
|
+
`sys-buddy-data` volume for the SQLite DB. Defaults to `serve` (auth-enforced) — never
|
|
38
|
+
`local`, which is unauthenticated and must not be reachable off-box. A `Makefile`
|
|
39
|
+
wraps the common flows and `.env.example` documents the tunnel setup for remote use.
|
|
40
|
+
|
|
41
|
+
### Backlog
|
|
42
|
+
- Tracked in `v2.md` — stronger auth (mTLS / OAuth 2.1); image/screenshot attachments;
|
|
43
|
+
non-HTTP / `interface_type` contracts; auto-revoke on completion + reopenable tasks +
|
|
44
|
+
token timer; multi-process presence & wait-cap accounting.
|
|
45
|
+
|
|
46
|
+
## [1.1.1] — 2026-07-24
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
- **Broker crashed on startup against a database created before 1.1.0.** The index on
|
|
50
|
+
`contracts(todo_id)` was declared in the schema block, which runs *before* the
|
|
51
|
+
migration that adds the column. On a fresh database the table is created with the
|
|
52
|
+
column so it worked; on an existing (pre-todos) database the `CREATE TABLE IF NOT
|
|
53
|
+
EXISTS` was a no-op and the index creation raised `no such column: todo_id`, aborting
|
|
54
|
+
boot. The index is now created after the migrations, once the column is guaranteed to
|
|
55
|
+
exist. Regression test added exercising an existing pre-todos database — the whole
|
|
56
|
+
test suite used fresh databases, which is why this shipped in 1.1.0.
|
|
57
|
+
|
|
58
|
+
## [1.1.0] — 2026-07-24
|
|
59
|
+
|
|
60
|
+
Todos: a task can carry several deliverables instead of exactly one. Additive — a task
|
|
61
|
+
with no todos behaves and renders exactly as it did in 1.0.1.
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
- **Todos — several deliverables under one task.** Each todo has its own contract chain
|
|
65
|
+
and its own `proposed → locked → built → verified` march. Agent-proposed and
|
|
66
|
+
peer-accepted, with no human approval gate (the same authority `propose_contract`
|
|
67
|
+
already had). Proposing IS the creator's consent, so you cannot propose work that
|
|
68
|
+
binds only other people; accepting agrees on WHAT, while the contract on that todo is
|
|
69
|
+
a separate, later agreement about HOW. Declines are recorded as a list beside the
|
|
70
|
+
acceptances (with a reason) rather than a status a state machine would have to unwind;
|
|
71
|
+
`repropose_todo` issues a new version and resets every acceptance, so nobody is held
|
|
72
|
+
to a scope they did not read. Dropping is mutual — every named party consents — with
|
|
73
|
+
a host override via `sys-buddy todo drop`.
|
|
74
|
+
- **Seats are not participants.** A todo reuses the task's existing seats and names
|
|
75
|
+
which of them it binds. A seat that is not a party can read the todo, but is not bound
|
|
76
|
+
by it, is not in its contract's quorum, and does not block it.
|
|
77
|
+
- **Todos on the dashboard.** The stepper TRUNCATES to three nodes (`open`,
|
|
78
|
+
`pre-flight assessments`, `todos`) when a task has todos, the last carrying a progress
|
|
79
|
+
bar and the `⚠ N awaiting acceptance` count; the five later phases move INTO each todo
|
|
80
|
+
as a mini-stepper. The right column becomes the todo LIST, pending first with a `⚠`;
|
|
81
|
+
selecting a todo swaps the panel to that todo's own contract card. ONE message thread
|
|
82
|
+
for the task, with a `⟨todo⟩` chip marking which deliverable a message belongs to. The
|
|
83
|
+
task-list row gains the same rollup (`2/6 verified ⚠1`).
|
|
84
|
+
- **Always-listening presence.** An agent parked in `wait_for_message` shows a live
|
|
85
|
+
pulsing dot and a `listening — 42m` streak on the dashboard. Stored as an EXPIRY, not
|
|
86
|
+
a boolean, so a broker that dies with agents parked cannot leave rows claiming to be
|
|
87
|
+
listening forever.
|
|
88
|
+
- **`releases/` + `features/` write-ups.** `features/v1.1.0/` carries the release notes,
|
|
89
|
+
eight dashboard screenshots (light and dark), and `seed_demo.py`, which reproduces
|
|
90
|
+
every screen locally in three commands.
|
|
91
|
+
|
|
92
|
+
### Changed
|
|
93
|
+
- **A task's state is now DERIVED from its todos, not set by an agent.** Agents no
|
|
94
|
+
longer call `_transition` on a task that has todos. This is agent-visible behaviour,
|
|
95
|
+
and it is the reason todos was worth the cost: a rollup cannot disagree with its parts
|
|
96
|
+
the way an agent-set task state can drift from them. `verified` requires ALL live
|
|
97
|
+
todos; `stuck` is never derived, because one stuck deliverable must not freeze the
|
|
98
|
+
other five.
|
|
99
|
+
- **Contract lock is pushed, not polled.** When a contract locks, the broker notifies
|
|
100
|
+
the roles that already signed instead of leaving them to poll.
|
|
101
|
+
- **`staging_url` is collected at host setup**, with validation strictness keyed to the
|
|
102
|
+
task's connectivity and `localhost` permitted for same-machine tasks.
|
|
103
|
+
- `messages.todo_id` is stored at post time; the dashboard's `⟨todo⟩` chip reads the
|
|
104
|
+
column rather than scraping "todo #N" out of prose, with the regex kept only as a
|
|
105
|
+
fallback for rows written before the column existed.
|
|
106
|
+
- Decision D11 recorded: the dashboard never issues commands (read-only; it surfaces
|
|
107
|
+
state and tells the human what to type). The host's `[Drop todo]` affordance therefore
|
|
108
|
+
prints the CLI line to type instead of mutating anything.
|
|
109
|
+
- `CONTRIBUTING.md` expanded into a full contributor guide — fork-and-PR walkthrough
|
|
110
|
+
(including how to recover an existing clone that can't push), environment setup with
|
|
111
|
+
`uv`, branch/commit conventions, the "tests green **and** proven live in the local
|
|
112
|
+
dashboard" definition of done, the changelog requirement, and the security invariants
|
|
113
|
+
a patch must not break (`local` mode is unauthenticated; peer content is DATA).
|
|
114
|
+
- `README.md` now carries **Versioning and releases**, **Contributing**, and **License**
|
|
115
|
+
sections pointing at `CHANGELOG.md`, `CONTRIBUTING.md`, and `LICENSE`; the repo-layout
|
|
116
|
+
block lists the governance docs, and the stale test count is corrected.
|
|
117
|
+
|
|
118
|
+
### Migration
|
|
119
|
+
- None required. The `todos`, `todo_decisions` and `todo_drop_consents` tables and the
|
|
120
|
+
`contracts.todo_id` / `messages.todo_id` columns are added automatically on broker
|
|
121
|
+
start, `NULL` on every existing row.
|
|
122
|
+
- **Restart any long-running broker.** A process started before this release keeps
|
|
123
|
+
serving its old code against an unmigrated database, so none of the above appears.
|
|
124
|
+
|
|
125
|
+
## [1.0.1] — 2026-07-23
|
|
126
|
+
|
|
127
|
+
### Fixed
|
|
128
|
+
- **Dashboard thread ordering.** The message/event thread sorted by minute-precision
|
|
129
|
+
time, so items within the same minute — and message↔event interleaving — could
|
|
130
|
+
render out of creation order. The API (`_messages_for`, `_events_for`) now sends a
|
|
131
|
+
raw `created_at` timestamp per item, and the dashboard sorts by it (sub-second),
|
|
132
|
+
falling back to the old minute sort only if the API is stale — safe during a broker
|
|
133
|
+
restart, when `ui.html` (served from disk) can be newer than the running `api.py`.
|
|
134
|
+
|
|
135
|
+
## [1.0.0] — 2026-07-23
|
|
136
|
+
First tagged release — the sys-buddy broker for cross-human AI agent collaboration.
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
- **Broker over MCP (HTTP)** with two modes (local / remote); remote authenticates agents
|
|
140
|
+
by scoped bearer token, with `rotate_token` and single-use invites.
|
|
141
|
+
- **Pairing & onboarding** — invite links, browser join page, and a pywebview **desktop app**
|
|
142
|
+
(host a task / join as a buddy / wire Claude).
|
|
143
|
+
- **Pre-flight readiness** gate — agents must pass a short quiz (proving they read the Rules
|
|
144
|
+
of Engagement) before messaging or changing status.
|
|
145
|
+
- **Rules of Engagement** — standing counter-instructions against prompt injection (peer
|
|
146
|
+
messages are DATA; the only fetchable URL is the signed `staging_url`).
|
|
147
|
+
- **Messaging** — `send_message` (question / answer / status_update / contract_proposal),
|
|
148
|
+
directed or broadcast; `check_messages` / `wait_for_message` / `ack_messages`.
|
|
149
|
+
- **Contract flow** — `propose_contract` / `lock_contract` / `get_contract` /
|
|
150
|
+
`reopen_negotiations`: versioned, mutually-locked, immutable-once-locked.
|
|
151
|
+
- **Lifecycle** — `report_status` (ready / checked / blocked / verified / stuck; debug tasks
|
|
152
|
+
use resolved), with strikes.
|
|
153
|
+
- **Read-only dashboard** with live updates over SSE.
|
|
154
|
+
|
|
155
|
+
### Changed
|
|
156
|
+
- **`get_contract` now returns the PROPOSED contract**, not only locked ones: it exposes the
|
|
157
|
+
proposed shape plus who has signed / who is awaiting, with the **`staging_url` withheld
|
|
158
|
+
until every role signs**. This removes the "sign-then-see" deadlock where an assessor was
|
|
159
|
+
told to review via `get_contract` but saw nothing until it locked — which it can't do
|
|
160
|
+
until they sign. The `staging_url` stays the single trusted, signed source (SSRF-guarded).
|
|
161
|
+
|
|
162
|
+
[Unreleased]: https://github.com/tooney92/sys-buddy/compare/v1.1.1...HEAD
|
|
163
|
+
[1.1.1]: https://github.com/tooney92/sys-buddy/compare/v1.1.0...v1.1.1
|
|
164
|
+
[1.1.0]: https://github.com/tooney92/sys-buddy/compare/v1.0.1...v1.1.0
|
|
165
|
+
[1.0.1]: https://github.com/tooney92/sys-buddy/compare/v1.0.0...v1.0.1
|
|
166
|
+
[1.0.0]: https://github.com/tooney92/sys-buddy/releases/tag/v1.0.0
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# sys-buddy — working notes for Claude
|
|
2
|
+
|
|
3
|
+
sys-buddy is an authenticated, contract-enforcing MCP broker that lets two developers'
|
|
4
|
+
AI coding agents collaborate across the internet. **The broker enforces; agents request.**
|
|
5
|
+
Source of truth: `SPEC.md`. Build brief: `KICKOFF.md`. Deviations/decisions: `DECISIONS.md`.
|
|
6
|
+
|
|
7
|
+
## Stack
|
|
8
|
+
- Python 3.11+, FastMCP (HTTP transport), SQLite (WAL). Env & deps via **`uv`**.
|
|
9
|
+
- One process, three surfaces: `/mcp` (MCP tools) · `/pair` (pairing REST) · `/ui` + `/api/*` (read-only dashboard).
|
|
10
|
+
- Dashboard is a single self-contained file at `src/sys_buddy/ui.html`, served at `/ui`.
|
|
11
|
+
- Run the broker: `uv run sys-buddy local` (loopback `:8787`, no auth) or `uv run sys-buddy serve` (remote, auth enforced).
|
|
12
|
+
- Tests: `uv run pytest -q`.
|
|
13
|
+
|
|
14
|
+
## Local testing & deploy workflow (owner-directed)
|
|
15
|
+
- **We test LOCALLY.** A `git push` / publish is NEVER a prerequisite for testing. E2E runs
|
|
16
|
+
against the **local** broker: `uv run sys-buddy local` on `:8787`, driving the dashboard at
|
|
17
|
+
`http://127.0.0.1:8787/ui` with **Playwright**. Backend behaviour is covered by `pytest`.
|
|
18
|
+
- **Push/publish happens ONLY on the owner's explicit directive, and ONLY AFTER** local pytest +
|
|
19
|
+
Playwright are green — never to unblock a test.
|
|
20
|
+
- The dashboard needs a viewer token. Mint one against the **local** db with
|
|
21
|
+
`uv run sys-buddy host-viewer`, then open `/ui?v=<token>`. Ask for seeds against the LOCAL db —
|
|
22
|
+
never "deploy + seed on a remote."
|
|
23
|
+
- If a task needs data, **CREATE it via the real flow first** (`task create` → `propose_contract`
|
|
24
|
+
→ `lock_contract` → `report_status`) rather than waiting on a seed.
|
|
25
|
+
|
|
26
|
+
## Feature DONE
|
|
27
|
+
= `pytest` green **AND** the change proven live in Playwright against the local dashboard.
|
|
28
|
+
|
|
29
|
+
## "pwr" — prove it live
|
|
30
|
+
When the owner says **"pwr"**, drive the just-finished change in a real browser via the Playwright
|
|
31
|
+
MCP: boot a seeded local broker, navigate the dashboard, screenshot the relevant screens
|
|
32
|
+
(list, task view, light + dark, mobile), and confirm it actually works before reporting done.
|
|
33
|
+
|
|
34
|
+
## Playwright MCP
|
|
35
|
+
Declared in `.mcp.json` (tracked) and auto-approved via `enabledMcpjsonServers` in
|
|
36
|
+
`.claude/settings.local.json`. MCP tools bind at session start — a freshly added server needs a
|
|
37
|
+
session restart to load.
|