Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8447093
Merge pull request #12 from protoLabsAI/dev
mabry1985 Apr 19, 2026
a39ac54
Merge pull request #13 from protoLabsAI/staging
mabry1985 Apr 19, 2026
f14b2fd
chore: release v0.2.0
Apr 19, 2026
305756e
Merge pull request #19 from protoLabsAI/dev
mabry1985 Apr 20, 2026
c73b487
Merge pull request #20 from protoLabsAI/staging
mabry1985 Apr 20, 2026
e7a5620
chore: release v0.2.1
Apr 20, 2026
f1dcd3f
chore(ci): update repo homepage after docs deploy (#149)
mabry1985 Apr 22, 2026
f49c012
feat(ui): live-edit config drawer with model discovery + SOUL.md editor
mabry1985 Apr 23, 2026
a406cd1
feat: first-run setup wizard + autostart + SOUL presets
mabry1985 Apr 23, 2026
4f74c7f
fix(ui): sync wizard/chat visibility on every page load
mabry1985 Apr 23, 2026
2cb089b
Merge pull request #152 from protoLabsAI/dev
mabry1985 Apr 23, 2026
a2c5b5b
fix(llm): override OpenAI SDK User-Agent to bypass gateway WAF
mabry1985 Apr 23, 2026
4ef3a5f
Merge pull request #153 from protoLabsAI/staging
mabry1985 Apr 23, 2026
acf2bd6
fix(review): address PR #150 review feedback
mabry1985 Apr 23, 2026
6f708f8
fix(review-2): address round-2 PR #150 feedback
mabry1985 Apr 23, 2026
3c25c41
Merge pull request #150 from protoLabsAI/feat/config-drawer-live-reload
mabry1985 Apr 23, 2026
433b44e
feat: ship default knowledge store + side-effect-verified eval harness
mabry1985 Apr 27, 2026
4d0d428
fix(review): address PR #155 CodeRabbit feedback
mabry1985 Apr 27, 2026
cab3bd8
fix(review-2): address round-2 PR #155 CodeRabbit feedback
claude Apr 27, 2026
b3a9f1d
fix(review-3): address round-3 PR #155 CodeRabbit feedback
mabry1985 Apr 27, 2026
b713d8d
fix(review-4): address round-4 PR #155 CodeRabbit feedback
claude Apr 27, 2026
ae752a5
chore: add uv.lock generated during round-4 review session
claude Apr 27, 2026
3749914
Merge pull request #155 from protoLabsAI/feat/default-kb-and-eval-har…
mabry1985 Apr 27, 2026
0609c67
feat: ship pluggable scheduler (local sqlite + Workstacean adapter)
mabry1985 Apr 28, 2026
7d1da5e
fix(review): address round-1 CodeRabbit findings on scheduler PR
claude Apr 28, 2026
1a05278
fix(review-2): address round-2 PR #156 CodeRabbit feedback
mabry1985 Apr 28, 2026
8b79fa8
feat(scheduler): YAML opt-out via middleware.scheduler (symmetric wit…
mabry1985 Apr 28, 2026
7ce3f10
fix(review-3+4): address rounds 3 + 4 PR #156 CodeRabbit feedback
mabry1985 Apr 28, 2026
3098908
fix(review-5): address round-5 PR #156 CodeRabbit feedback
mabry1985 Apr 28, 2026
ec86865
Merge pull request #156 from protoLabsAI/feat/agent-scheduler
mabry1985 Apr 28, 2026
16337ca
docs: sync surface counts and add scheduler/memory tool coverage
mabry1985 Apr 28, 2026
bf2eb12
Merge pull request #157 from protoLabsAI/docs/sync-after-kb-and-sched…
mabry1985 Apr 28, 2026
a4b7c65
chore: conform to workspace-config standard (.beads + .automaker base…
mabry1985 May 25, 2026
ccd6656
chore(ci): migrate node/git workflows to org-owned runner
May 25, 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
3 changes: 3 additions & 0 deletions .automaker/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": 1
}
Empty file added .beads/issues.jsonl
Empty file.
1 change: 1 addition & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ env:

jobs:
build-and-push:
# workspace-config: allow-hosted-runner docker buildx build + registry push
runs-on: ubuntu-latest
timeout-minutes: 30

Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Deploy docs to GitHub Pages
on:
push:
branches: [main]
paths: ['docs/**', 'package.json', 'package-lock.json']
paths: ["docs/**", "package.json", "package-lock.json"]
workflow_dispatch:

permissions:
Expand All @@ -18,7 +18,7 @@ concurrency:

jobs:
build:
runs-on: ubuntu-latest
runs-on: namespace-profile-protolabs-linux
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -33,6 +33,7 @@ jobs:

deploy:
needs: build
# workspace-config: allow-hosted-runner GitHub Pages deploy requires the hosted Pages environment
runs-on: ubuntu-latest
environment:
name: github-pages
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: 'Prepare Release'
name: "Prepare Release"

# Runs after any non-release PR merges to main, OR manually.
# Bumps the version in pyproject.toml, opens a prepare-release/vX.Y.Z
Expand All @@ -14,13 +14,13 @@ on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type'
description: "Version bump type"
required: true
type: choice
options: [patch, minor, major]
default: patch
dry_run:
description: 'Preview only — no branch or PR created'
description: "Preview only — no branch or PR created"
type: boolean
default: false

Expand All @@ -31,7 +31,7 @@ concurrency:
jobs:
prepare:
name: Prepare Release
runs-on: ubuntu-latest
runs-on: namespace-profile-protolabs-linux
# Guards:
# - repo-scope: don't run in forks
# - workflow_dispatch always runs
Expand Down Expand Up @@ -63,7 +63,7 @@ jobs:

- uses: actions/setup-python@v5
with:
python-version: '3.12'
python-version: "3.12"

- name: Bump version
run: python scripts/version.py ${{ inputs.bump || 'patch' }}
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: 'Release'
name: "Release"

# Triggered by a push of a vX.Y.Z tag (cut by prepare-release.yml).
# Builds and pushes the stable semver Docker tags, creates a GitHub
Expand All @@ -9,11 +9,11 @@ name: 'Release'
on:
push:
tags:
- 'v*.*.*'
- "v*.*.*"
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g. v0.1.1)'
description: "Tag to release (e.g. v0.1.1)"
required: true

env:
Expand All @@ -23,6 +23,7 @@ env:
jobs:
release:
name: Release
# workspace-config: allow-hosted-runner docker buildx build + registry push
runs-on: ubuntu-latest
if: github.repository == 'protoLabsAI/protoAgent'
permissions:
Expand Down Expand Up @@ -130,7 +131,7 @@ jobs:

- uses: actions/setup-node@v4
with:
node-version: '20'
node-version: "20"

- name: Post release notes to Discord
continue-on-error: true
Expand Down
15 changes: 14 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ __pycache__/
*.pyo
.env
.venv/
.venv-*/
venv/

# Local-run artifacts — autostart stdout/stderr logs + memory middleware
# fallback directory when /sandbox is not available.
logs/
.proto/
*.egg-info/
dist/
build/
Expand All @@ -13,7 +19,6 @@ build/

# protoLabs Studio agent workspace (never commit)
.automaker-lock
.automaker/
.claude/
.worktrees/
worktrees/
Expand All @@ -22,3 +27,11 @@ worktrees/
node_modules/
docs/.vitepress/dist/
docs/.vitepress/cache/

# protoLabs workspace-config standard
.beads/beads.db
# Git-friendly issue export must be committed despite the blanket *.jsonl ignore.
!.beads/issues.jsonl
.automaker/features/
.automaker/checkpoints/
.automaker/trajectory/
23 changes: 22 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ RUN useradd -m -s /bin/bash -u ${SANDBOX_UID} sandbox
# auth, add them here. The ddgs + beautifulsoup4 pair powers the
# starter web_search / fetch_url tools; drop them if you strip those.
RUN pip install --no-cache-dir \
gradio httpx uvicorn langfuse prometheus-client pyyaml \
gradio httpx uvicorn langfuse prometheus-client pyyaml 'ruamel.yaml>=0.18' \
langchain langchain-openai langgraph websockets \
ddgs beautifulsoup4

Expand All @@ -40,6 +40,27 @@ RUN chmod +x /opt/protoagent/entrypoint.sh
RUN mkdir -p /sandbox /tmp/sandbox /sandbox/audit /sandbox/knowledge \
&& chown -R sandbox:sandbox /sandbox /tmp/sandbox

# Make /opt/protoagent/config writable by the sandbox user so the
# drawer and setup wizard can persist edits from inside the container.
RUN chown -R sandbox:sandbox /opt/protoagent/config

# Declare config as a volume so setup completion (``.setup-complete``
# marker + any YAML / SOUL.md edits) survives ``docker run`` without
# a -v flag.
#
# Lifecycle note: without an explicit mount, Docker creates an
# ANONYMOUS volume on every ``docker run``. Those accumulate and the
# volume is NOT removed when the container is removed unless you pass
# ``--rm -v``. For long-lived deployments, use a named volume or a
# host mount so upgrades don't silently carry stale config forward:
#
# docker run -v my-agent-config:/opt/protoagent/config my-agent:latest
#
# or a bind mount:
#
# docker run -v /srv/my-agent/config:/opt/protoagent/config my-agent:latest
VOLUME ["/opt/protoagent/config"]

ENV PYTHONPATH=/opt/protoagent

USER sandbox
Expand Down
48 changes: 30 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ close to a rewrite of `SOUL.md`, `graph/prompts.py`, and
Quinn was the first agent built on this template — it's a good
example of what a filled-in fork looks like end-to-end.

Start a new agent by clicking **"Use this template"** at the top
of the GitHub repo. See [TEMPLATE.md](./TEMPLATE.md) for the
step-by-step fork checklist.
**Try it in 5 minutes:** clone, `pip install -r requirements.txt`,
`python server.py`, open <http://localhost:7870>, and walk the
setup wizard — no forking, no `sed`, no Docker required to get
your first agent talking. See the [first-agent tutorial](./docs/tutorials/first-agent.md).

**When you're ready to ship your own:** click **"Use this template"**
at the top of the GitHub repo, then follow [Customize &
deploy](./docs/guides/customize-and-deploy.md) for the fork /
rename / release-pipeline wiring.

## What you get out of the box

Expand All @@ -24,35 +30,41 @@ step-by-step fork checklist.
| Agent runtime | `graph/agent.py`, `server.py` | LangGraph `create_agent()` wired to the A2A handler, with streaming token capture for cost-v1 |
| LLM gateway | `graph/llm.py` | OpenAI-compatible client pointed at LiteLLM — swap models by editing the gateway config, not the fork |
| Subagents | `graph/subagents/config.py` | DeerFlow-pattern delegation via a `task()` tool; one placeholder `worker` ships |
| Starter tools | `tools/lg_tools.py` | Free, keyless tools so a fresh fork can demo real behaviour: `echo`, `current_time`, `calculator` (safe AST eval), `web_search` (DuckDuckGo), `fetch_url` |
| Starter tools | `tools/lg_tools.py` | Twelve tools default-on: 4 keyless general (`current_time`, `calculator` safe AST eval, `web_search` via DuckDuckGo, `fetch_url`) + 5 memory (`memory_ingest`, `memory_recall`, `memory_list`, `memory_stats`, `daily_log`) bound to the KB store + 3 scheduler (`schedule_task`, `list_schedules`, `cancel_schedule`) bound to the scheduler backend |
| Knowledge store | `knowledge/store.py` | sqlite + FTS5 (LIKE fallback). One `chunks` table for operator notes, daily-log entries, and conversation findings. Default-on; turn off with `middleware.knowledge: false` |
| Scheduler | `scheduler/` | `schedule_task` / `list_schedules` / `cancel_schedule` tools backed by either a bundled sqlite scheduler or a Workstacean adapter (env-selected). Multi-agent-safe — every job is namespaced by `AGENT_NAME`. See [Schedule future work](./docs/guides/scheduler.md) |
| Eval harness | `evals/` | Side-effect-verified A2A test harness — audit log + reply text + KB state. `python -m evals.runner` against a running agent. See [Eval your fork](./docs/guides/evals.md) |
| Tracing | `tracing.py` | Langfuse trace_session with distributed `a2a.trace` propagation and the OTel cross-context-detach filter |
| Observability | `metrics.py`, `audit.py` | Prometheus metrics with per-agent prefix, JSONL audit log with trace IDs |
| Output protocol | `graph/output_format.py` | `<scratch_pad>` / `<output>` parsing so the model can think without it leaking to users |
| UI | `chat_ui.py`, `static/` | Gradio chat with PWA shell, dark theme, offline fallback |
| Release pipeline | `.github/workflows/*.yml` | Autonomous semver bumps, GHCR image push, GitHub release with filtered notes, optional Discord post |

## Quickstart
## Quickstart — from zero to chatting in 5 minutes

```bash
# 1. Click "Use this template" on GitHub, or:
gh repo create protoLabsAI/my-agent \
--template protoLabsAI/protoAgent \
--public --clone

# 1. Get the code (no fork needed for a first run)
git clone https://github.com/protoLabsAI/protoAgent.git my-agent
cd my-agent

# 2. Rename the agent (one env var, read by server.py, metrics, tracing)
export AGENT_NAME=my-agent
# 2. Install deps into a venv
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# 3. Boot the container
docker build -t my-agent:local .
docker run --rm -p 7870:7870 -e AGENT_NAME=my-agent my-agent:local
# 3. Run the server — no env vars required
python server.py

# 4. Hit the agent card
curl http://localhost:7870/.well-known/agent-card.json
# 4. Open the wizard — pick your endpoint, pick a model, name the
# agent, pick a persona preset, hit Launch. The chat UI appears
# on the same page.
open http://localhost:7870
```

See [TEMPLATE.md](./TEMPLATE.md) for the full fork checklist.
[First-agent tutorial](./docs/tutorials/first-agent.md) walks
through every wizard step with screenshots.

Once you're happy and want to ship it as your own image in your
own GHCR: [Customize & deploy](./docs/guides/customize-and-deploy.md).

## Architecture

Expand Down
54 changes: 50 additions & 4 deletions TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Fork checklist

> **Most of what used to be in this file is now a runtime wizard**
> that runs on first page load. Model, tools, persona, name, auth,
> autostart — all captured without editing code. See
> [first-agent tutorial](./docs/tutorials/first-agent.md).
>
> This checklist is only for forks that want to ship their own
> container image under their own GitHub org — the structural
> changes the wizard can't do. For most of that, the new
> [Customize & deploy](./docs/guides/customize-and-deploy.md)
> guide is the canonical source. This file stays for back-compat.

You clicked "Use this template" (or ran `gh repo create --template`).
Now what?

Expand Down Expand Up @@ -61,10 +72,10 @@ handler's output extraction depends on it.
## 4. Add your real tools

`tools/lg_tools.py` ships with a small keyless starter set so a
fresh clone can demonstrate a real research loop: `echo`,
`current_time`, `calculator` (safe AST eval — no `eval()`),
`web_search` (DuckDuckGo via `ddgs`), and `fetch_url`. Keep the
ones you want, drop the rest, and add your own:
fresh clone can demonstrate a real research loop: `current_time`,
`calculator` (safe AST eval — no `eval()`), `web_search` (DuckDuckGo
via `ddgs`), and `fetch_url`. Keep the ones you want, drop the rest,
and add your own:

```python
from langchain_core.tools import tool
Expand Down Expand Up @@ -156,6 +167,41 @@ your fork. A useful pattern:
- Extend `tests/test_a2a_integration.py` with assertions for
your declared skills + extensions on the agent card

For end-to-end behaviour testing — "when the operator asks X, does
the right tool actually fire and the right row land in the KB?" —
the template ships an eval harness under `evals/`:

```bash
python -m evals.runner # against a running agent
python -m evals.runner --category tool
```

See [Eval your fork](./docs/guides/evals.md) for what each case
asserts, how the three assertion channels work, and how to add
cases for your fork's new tools.

## 9b. Scheduler — local sqlite or Workstacean

The bundled scheduler ships three agent tools — `schedule_task`,
`list_schedules`, `cancel_schedule` — backed by either a local
sqlite poller or a Workstacean adapter, selected at startup via env:

```bash
# Default: local sqlite, persists at /sandbox/scheduler/<agent_name>/jobs.db
python server.py

# Workstacean: set both and restart
export WORKSTACEAN_API_BASE=http://your-workstacean:3000
export WORKSTACEAN_API_KEY=...
python server.py
```

Multi-fork safety: every job is namespaced by `AGENT_NAME`, so
spinning up `gina-personal` next to `gina-work` (or any number of
ginas under one Workstacean) doesn't cross-fire prompts. See
[Schedule future work](./docs/guides/scheduler.md) for the full
firing model and integration notes.

## 9a. Understand the skill loop

protoAgent's skill loop lets your agent learn from experience automatically.
Expand Down
Loading