| Directory | Component | Stack |
|---|---|---|
shared |
Shared models, scoring, schema | Python, Pydantic |
plugins/acq/server |
MCP server (plugin) | Python, FastMCP |
team-api |
Team Q&A API | Python, FastAPI |
team-ui |
Review dashboard | TypeScript, SvelteKit, Tailwind |
git clone https://github.com/seanmeyer/acq.git
cd acq
make setupThe quickest way to run everything is with Docker Compose.
Export the required secret first:
export ACQ_JWT_SECRET=dev-secretStart all services (runs in the foreground):
make compose-upIn a separate terminal, create a user:
make seed-users USER=demo PASS=demo123The team API is available at http://localhost:8742.
The review UI is available at http://localhost:3000.
For isolated component testing outside Docker, use make dev-api (team API) and make dev-ui (dashboard).
Run make setup — it installs dependencies and runs scripts/setup-agent.py which
authenticates via GitHub device flow and writes credentials to ~/.claude/settings.json.
To point your agent at a local team API instance:
{
"env": {
"ACQ_TEAM_ADDR": "http://localhost:8742",
"ACQ_TEAM_API_KEY": "default-key"
}
}The team API and review UI are bundled into a single Docker image and deployed to Howler (service ID 222). The Dockerfile uses a multi-stage build: Node builds the SvelteKit UI, then the Python image copies in the static assets and serves them via FastAPI.
These are configured via the Howler UI or API at /api/services/222/secrets/:
| Secret | Purpose |
|---|---|
ACQ_JWT_SECRET |
Signs session JWTs |
ACQ_API_KEYS |
JSON map of static API key → agent name (dev/test fallback only) |
ORGSTORE_CLUSTER |
DogPark cluster name (dogpark) — enables Postgres |
DB_NAME |
DogPark database name (dev_db_acq) |
DB_USER |
DogPark database role (dev_db_acq) |
DB_HOST |
pg-proxy host (auto-derived if not set) |
GITHUB_CLIENT_ID |
GitHub OAuth app client ID |
GITHUB_CLIENT_SECRET |
GitHub OAuth app client secret |
The team API uses a DogPark developer database (dev_db_acq on the dogpark cluster).
DogPark's default roles lack CREATE permission, so DDL changes must be run via the
admin bypass role in the toolbox. Do not use orgstore toolbox psql — it connects
as the default role which cannot create tables.
To run DDL (from a machine with kubectl access — not workspaces):
DEV_DB=dev_db_acq
kubectl exec \
--context gizmo.us1.staging.dog \
--namespace orgstore-dogpark \
-it \
deployment/orgstore-dogpark-toolbox -- \
pg-wrap -o dogpark -b admin -D $DEV_DB psqlThe -b admin flag is critical — it bypasses the default role and connects with
CREATE permission on the dogpark schema. You can then run any DDL:
CREATE TABLE IF NOT EXISTS dogpark.my_new_table (...);Note: DogPark is not compatible with PG Schema Manager (PGSM/Alembic). DDL changes are manual via the toolbox. See the DogPark Confluence page for details.
Build a tarball with the Dockerfile at root and deploy:
tmpdir=$(mktemp -d)
cp team-api/Dockerfile "$tmpdir/Dockerfile"
cp -r shared team-api team-ui "$tmpdir/"
tar czf /tmp/acq-deploy.tar.gz -C "$tmpdir" .
curl -X POST "https://howler.us1.staging.dog/api/services/222/builds/" \
-F "build-context.tgz=@/tmp/acq-deploy.tar.gz"The response streams build and deploy logs. The field name must be build-context.tgz — any other name returns a silent 500.
The service is live at https://acq-team-api.us1.staging.dog/ once the deploy finishes. Fabric destinations and routing domains are already configured.
Production uses GitHub OAuth — users click "Sign in with GitHub" and their GitHub username becomes their identity. The GitHub OAuth app is registered at github.com/settings/applications with callback URL https://acq-team-api.us1.staging.dog/auth/callback.
Local dev (docker-compose) still uses username/password via make seed-users.
| Command | Purpose |
|---|---|
make compose-up |
Build and start services |
make compose-down |
Stop services |
make compose-reset |
Stop services and wipe database |
make seed-users USER=demo PASS=demo123 |
Create a user |
| Command | Purpose |
|---|---|
make lint |
Format and lint all Python components |
make test |
Run tests across shared, team-api, and MCP server |