Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
2306eb8
docs: single sequencing spine — DIRECTION.md (owner-ratified 2026-07-27)
hachej Jul 27, 2026
d98557e
Merge pull request #974 from hachej/docs/unified-roadmap
hachej Jul 27, 2026
535d57f
#909 fix(agent): make CSS builds CWD-independent
hachej Jul 27, 2026
eb6b02f
Merge pull request #975 from hachej/issue-909/css-build-fix
hachej Jul 27, 2026
0863c18
#909 feat(front): keep reload reconnect streams addressed
hachej Jul 27, 2026
da608fc
#909 feat(front): select addressed agents dynamically
hachej Jul 27, 2026
cea04aa
#909 feat(front): opt full app into addressed agents
hachej Jul 27, 2026
b2b6afd
#909 test(e2e): prove two-agent addressed browser wire
hachej Jul 27, 2026
2c551ad
#909 feat(front): restore mobile agent touch target
hachej Jul 27, 2026
ec61087
#909 feat(front): settle terminal reload tool state
hachej Jul 27, 2026
a9892ca
#909 test(e2e): run addressed fixture in direct mode
hachej Jul 27, 2026
bc338c1
#909 test(e2e): synchronize addressed fixture lifecycle
hachej Jul 27, 2026
4552e47
Merge pull request #976 from hachej/issue-909/front-addressing
hachej Jul 27, 2026
8cba25e
#909 feat(console): switcher + grouping
hachej Jul 28, 2026
b34e9c6
#909 feat(console): presence
hachej Jul 28, 2026
60bc47d
#909 feat(console): switch-preserves-state
hachej Jul 28, 2026
599be0a
#909 feat(console): E2E
hachej Jul 28, 2026
fc54528
#909 fix(console): size empty-state touch target
hachej Jul 28, 2026
c2355d6
#909 fix(console): stabilize empty multi-agent state
hachej Jul 28, 2026
c69f033
#909 test(console): allow full-app import startup
hachej Jul 28, 2026
930c48d
Merge pull request #981 from hachej/issue-909/console-ux
hachej Jul 28, 2026
022742d
#909 fix: re-land native session adoption and rename menu
hachej Jul 28, 2026
c46203d
Merge pull request #982 from hachej/issue-909/native-session-reland
hachej Jul 28, 2026
5cc8e88
#909 fix(workspace): show multi-agent chats in splits
hachej Jul 28, 2026
c78d8e4
Merge pull request #983 from hachej/issue-909/split-panes
hachej Jul 28, 2026
9737cd1
#909 feat(console): add addressed agent chat actions
hachej Jul 29, 2026
08db89b
#909 feat(console): cover per-agent chat creation in e2e
hachej Jul 29, 2026
0a27c5d
#909 fix(console): meet mobile touch-target minimum on per-agent chat…
hachej Jul 29, 2026
b8596e8
#909 fix(console): preserve touch actions without hover
hachej Jul 29, 2026
811c36f
#909 fix(console): preserve cross-agent chat panes
hachej Jul 29, 2026
b4948ca
Merge pull request #986 from hachej/issue-909/per-agent-new-chat
hachej Jul 29, 2026
4abff59
#909 feat(workspace): boot real two-agent playground fleet
hachej Jul 29, 2026
04870ac
#909 test(agent): prove per-agent capability isolation
hachej Jul 29, 2026
388e080
Merge pull request #990 from hachej/issue-909/bead-38
hachej Jul 29, 2026
bd70a29
#909 test(workspace): fix addressed-agent e2e startup
hachej Jul 29, 2026
44dd0c3
Merge integration/wave-1 into bead-36 (union: real fleet + scripted c…
hachej Jul 29, 2026
6002387
Merge pull request #992 from hachej/issue-909/bead-36
hachej Jul 29, 2026
d96c698
Merge origin/main into integration/wave-1 — reconciled per orchestrat…
hachej Jul 29, 2026
079ac61
#909 feat(console): label panes and restore per-agent chat controls
hachej Jul 30, 2026
af351cf
Merge pull request #993 from hachej/issue-909/ui-agent-labels
hachej Jul 30, 2026
3cee43e
#909 feat(console): restructure left pane and restore pin feedback
hachej Jul 30, 2026
e5e72fb
#909 fix(console): size touch targets and scope E2E rows
hachej Jul 30, 2026
65558bb
Merge pull request #999 from hachej/issue-909/left-pane-restructure
hachej Jul 30, 2026
fcbdea9
#909 refactor(console): simplify left pane to Agents / Pinned / Chats
hachej Jul 30, 2026
3cffed2
Merge pull request #1002 from hachej/issue-909/left-pane-simplify
hachej Jul 30, 2026
f771af0
#909 refactor(console): render agent rows with icon actions
hachej Jul 30, 2026
e378276
#909 refactor(console): restore workspace disclosure
hachej Jul 30, 2026
52a29ae
#909 refactor(console): preserve agent touch targets
hachej Jul 30, 2026
7f1f36a
#909 refactor(console): show active chat filter icon
hachej Jul 30, 2026
621cb04
#909 refactor(console): keep chat filter unchanged
hachej Jul 30, 2026
ae535c7
#909 refactor(console): restore stateful chat filter
hachej Jul 30, 2026
cdcb304
Merge pull request #1003 from hachej/issue-909/agent-row-icons
hachej Jul 30, 2026
780cff0
#909 fix(console): unify pane rows without agent hover
hachej Jul 30, 2026
4ae4b50
#909 fix(console): harden agent row hover assertions
hachej Jul 30, 2026
140a670
Merge pull request #1004 from hachej/issue-909/agent-row-hover
hachej Jul 30, 2026
d2faf71
#909 test(ci): gate full-app e2e, unpin/delete, and section collapse
hachej Jul 30, 2026
89ee641
#909 test(ci): build automation before full-app migration
hachej Jul 30, 2026
305c0c5
#909 test(ci): prebuild full-app dependency graph
hachej Jul 30, 2026
cb047f6
#909 test(ci): allow isolated full-app test runtime
hachej Jul 30, 2026
4cc1c6b
#909 test(ci): expose app plugins to auth harness
hachej Jul 30, 2026
c889437
#909 fix(console): surface gateway errors and mark orphaned sessions …
hachej Jul 30, 2026
a488810
#909 fix(console): merge integration wave 1
hachej Jul 30, 2026
46174f8
#909 test(ci): align full-app harness with addressed agents
hachej Jul 30, 2026
9f45fb0
#909 test(ci): update full-app browser fixtures
hachej Jul 30, 2026
86f905e
#909 test(ci): align full-app fixtures with runtime contracts
hachej Jul 31, 2026
3e51642
#909 test(ci): open current full-app workbench sources
hachej Jul 31, 2026
3d599dc
#909 test(ci): follow current full-app interaction contracts
hachej Jul 31, 2026
8fa75b7
#909 test(ci): align lifecycle spec with plugin-tabs files
hachej Jul 31, 2026
f01cd06
#909 test(ci): assert lifecycle markdown through raw editor
hachej Jul 31, 2026
ca9ec91
Merge pull request #1005 from hachej/issue-909/ci-gates
hachej Jul 31, 2026
150fb30
Merge pull request #1006 from hachej/issue-909/orphaned-sessions
hachej Jul 31, 2026
d0ff9e6
Merge remote-tracking branch 'origin/main' into integration/wave-1-final
hachej Jul 31, 2026
062ee1f
#909 fix(workspace): stabilize multi-chat navigation
hachej Jul 31, 2026
c52eb17
fix: stabilize wave-1 final verification
hachej Jul 31, 2026
b6c697b
#909 fix(agent): hide stale deleted sessions
hachej Jul 31, 2026
510ec36
#909 fix(agent): retain delete tombstones across pages
hachej Jul 31, 2026
e7b50bf
Merge pull request #1007 from hachej/fix/909-wave1-session-navigation
hachej Jul 31, 2026
64c89eb
Merge remote-tracking branch 'origin/integration/wave-1' into integra…
hachej Jul 31, 2026
5600946
#909 test(ci): seed workspace playground e2e fixtures
hachej Jul 31, 2026
bb0dcf9
#909 fix(agent): stabilize runtime scope identity
hachej Jul 31, 2026
1bfb838
#909 fix: close wave-one session review gaps
hachej Jul 31, 2026
c2bc919
#909 fix(full-app): make dev console smoke deterministic
hachej Jul 31, 2026
1694f73
#391 ci(release): gate cuts on built-dist smoke
hachej Jul 31, 2026
ebb504d
Merge pull request #1019 from hachej/fix/wave1-exit-26
hachej Jul 31, 2026
26181fc
#909 fix(agent): harden runtime identity migration
hachej Jul 31, 2026
aabec16
#909 fix(full-app): harden concurrent dev smoke
hachej Jul 31, 2026
98ca8ec
#909 fix(agent): prove target before pin migration
hachej Jul 31, 2026
069d217
#391 fix(release): close RC gate safety gaps
hachej Jul 31, 2026
c2c6855
#909 fix(full-app): remove owned smoke temp roots
hachej Jul 31, 2026
ae4baa3
#909 fix(agent): gate legacy session mutations
hachej Jul 31, 2026
6e8c121
#391 fix(release): atomically bind release tags
hachej Jul 31, 2026
d5db667
#391 fix(release): compare-and-delete local candidate tag
hachej Jul 31, 2026
2e10d28
#909 fix(agent): preserve verified legacy binding affinity
hachej Jul 31, 2026
9177685
Merge pull request #1021 from hachej/fix/wave1-exit-32
hachej Jul 31, 2026
7b1d474
Merge pull request #1022 from hachej/fix/wave1-exit-33
hachej Jul 31, 2026
35951e1
#909 fix(agent): preserve legacy not-found projection
hachej Jul 31, 2026
742bf19
Merge pull request #1020 from hachej/fix/wave1-runtime-identity
hachej Jul 31, 2026
f072022
#909 merge: reconcile Wave 1 with latest main
hachej Jul 31, 2026
ac41170
#909 fix(full-app): restore addressed fleet discovery
hachej Jul 31, 2026
bb2d616
Merge pull request #1023 from hachej/fix/wave1-main-reconcile
hachej Jul 31, 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
69 changes: 67 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: CI

on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
push:
branches:
- main
Expand Down Expand Up @@ -466,6 +467,68 @@ jobs:

- name: Run e2e
run: pnpm e2e
env:
# The workspace-playground config seeds this clean override from its
# committed fixtures, matching a fresh checkout instead of relying on
# mutable local playground state.
BORING_AGENT_WORKSPACE_ROOT: ${{ runner.temp }}/workspace-playground-e2e

full-app-e2e:
name: Full App E2E
needs: changes
if: github.event_name == 'push' || needs.changes.outputs.e2e == 'true' || contains(github.event.pull_request.labels.*.name, 'ci:e2e') || contains(github.event.pull_request.labels.*.name, 'ci:full') || contains(github.event.pull_request.labels.*.name, 'release-candidate') || startsWith(github.head_ref, 'release/')
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: ubuntu
POSTGRES_PASSWORD: test
POSTGRES_DB: boring_ui_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.19.0
cache: pnpm

- name: Install
run: pnpm install --frozen-lockfile

- name: Build full-app dependencies
run: pnpm --filter 'full-app^...' --workspace-concurrency=4 run build
env:
NODE_OPTIONS: --max-old-space-size=4096

- name: Cache Playwright browsers
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-

- name: Install Playwright browser
run: pnpm exec playwright install --with-deps chromium

- name: Run full-app e2e
run: pnpm --filter full-app run e2e
env:
FULL_APP_E2E_DATABASE_URL: postgres://ubuntu:[email protected]:5432/boring_ui_test
NODE_OPTIONS: --max-old-space-size=4096

ui-review-fixture:
name: UI Review
Expand Down Expand Up @@ -672,7 +735,7 @@ jobs:
name: PR Fast Summary
if: always() && github.event_name == 'pull_request'
runs-on: ubuntu-latest
needs: [action-pins, lint, typecheck, unit-summary, invariants, bundle-budget, core-bundle-budget, e2e, remote-worker-smoke]
needs: [action-pins, lint, typecheck, unit-summary, invariants, bundle-budget, core-bundle-budget, e2e, full-app-e2e, remote-worker-smoke]
steps:
- name: Verify PR checks
run: |
Expand All @@ -685,6 +748,7 @@ jobs:
"bundle=${{ needs.bundle-budget.result }}" \
"core-bundle=${{ needs.core-bundle-budget.result }}" \
"e2e=${{ needs.e2e.result }}" \
"full-app-e2e=${{ needs.full-app-e2e.result }}" \
"worker-smoke=${{ needs.remote-worker-smoke.result }}"; do
name=${result%%=*}
value=${result#*=}
Expand All @@ -699,7 +763,7 @@ jobs:
name: Main Green Summary
if: always() && github.event_name == 'push'
runs-on: ubuntu-latest
needs: [action-pins, lint, typecheck, bundle-budget, core-bundle-budget, unit-summary, invariants, e2e, remote-worker-smoke]
needs: [action-pins, lint, typecheck, bundle-budget, core-bundle-budget, unit-summary, invariants, e2e, full-app-e2e, remote-worker-smoke]
steps:
- name: Verify main checks
run: |
Expand All @@ -712,6 +776,7 @@ jobs:
"unit=${{ needs.unit-summary.result }}" \
"invariants=${{ needs.invariants.result }}" \
"e2e=${{ needs.e2e.result }}" \
"full-app-e2e=${{ needs.full-app-e2e.result }}" \
"worker-smoke=${{ needs.remote-worker-smoke.result }}"; do
name=${result%%=*}
value=${result#*=}
Expand Down
65 changes: 65 additions & 0 deletions .github/workflows/release-candidate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Release Candidate Built-Dist

on:
pull_request:
types: [opened, synchronize, reopened, labeled]
push:
branches:
- main
- "release/**"

permissions:
contents: read

concurrency:
group: release-candidate-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }}
cancel-in-progress: true

jobs:
built-dist:
name: Release Candidate Built-Dist
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'release-candidate') || startsWith(github.head_ref, 'release/')
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: pnpm

- name: Install
run: pnpm install --frozen-lockfile

- name: Test release controls
run: node --test scripts/atomic-release-tag.test.mjs scripts/require-release-candidate-check.test.mjs scripts/validate-release-resume.test.mjs

- name: Build package and plugin release artifacts
run: pnpm build:packages
env:
NODE_OPTIONS: --max-old-space-size=4096

- name: Cache Playwright browsers
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-

- name: Install Playwright browser
run: pnpm exec playwright install --with-deps chromium

- name: Run built-dist release-candidate smoke
run: |
env -u BORING_RC_BREAK_CSS -u BORING_RC_BREAK_FIRST_SEND \
pnpm --filter workspace-playground run test:e2e:release-candidate
env:
BORING_PLAYGROUND_DIST_ONLY: "1"
BORING_AGENT_WORKSPACE_ROOT: ${{ runner.temp }}/workspace-playground-release-candidate
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Detailed coding practices, workflow, architecture, and package docs live under `
| Need | Read |
| --- | --- |
| Project/package map | [`docs/README.md`](docs/README.md) |
| **Single direction / sequencing spine** | [`docs/DIRECTION.md`](docs/DIRECTION.md) |
| Coding rules | [`docs/kanzen/procedures/coding-rules.md`](docs/kanzen/procedures/coding-rules.md) |
| Coding invariants | [`docs/kanzen/procedures/coding-invariants.md`](docs/kanzen/procedures/coding-invariants.md) |
| Repo commands | [`docs/kanzen/procedures/repo-commands.md`](docs/kanzen/procedures/repo-commands.md) |
Expand Down
19 changes: 14 additions & 5 deletions apps/full-app/.env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# HTTP
PORT=3000
HOST=0.0.0.0
HOST=127.0.0.1
LOG_LEVEL=info

# Database
DATABASE_URL=postgres://postgres:postgres@localhost:5432/boring_ui_v2
DATABASE_URL=postgres://boring:[email protected]:55439/boring_ui_v2

# Auth
BETTER_AUTH_SECRET=0000000000000000000000000000000000000000000000000000000000000000
Expand All @@ -14,9 +14,18 @@ CORS_ORIGINS=http://localhost:3000,http://localhost:5173
# Workspace settings encryption (32-byte hex)
WORKSPACE_SETTINGS_ENCRYPTION_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

# Mail transport
[email protected]
MAIL_TRANSPORT_URL=console://
# Local developer login. This is ignored when NODE_ENV=production.
ENABLE_DEV_LOGIN=1

# Keep email verification disabled for the zero-edit local flow. Uncomment both
# values to exercise verification/password-reset mail through the console transport.
# [email protected]
# MAIL_TRANSPORT_URL=console://
SEND_WELCOME_EMAIL=false

# Keep local workspaces and Pi sessions outside the checkout.
BORING_AGENT_WORKSPACE_ROOT=/tmp/boring-full-app-workspaces
BORING_AGENT_SESSION_ROOT=/tmp/boring-full-app-pi-sessions

# Optional
# Generic MCP/Sources plugin. COMPOSIO_API_KEY is read server-side only; never expose it through VITE_*.
Expand Down
36 changes: 25 additions & 11 deletions apps/full-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,24 @@ The smoke boots a local ephemeral `127.0.0.1` Fastify listener, registers `regis

## Run (local dev)

The committed smoke is the zero-edit proof from a clean checkout after `pnpm install`:

```bash
pnpm --filter full-app smoke:dev-console
```

That one command allocates free loopback ports for an isolated Postgres 16 service, the Fastify backend, and Vite; waits for Postgres; builds the app dependencies; applies all migrations using the unedited `.env.example` as its base; starts the full dev app; signs in through the allocated Vite `/dev-login`; reaches the authenticated workspace console; and requires HTTP 202 from one addressed prompt request. It also gives the run unique temporary workspace and session roots and constructs a hermetic child environment, so ambient mail, runtime-mode, or model settings cannot change the proof. It intercepts only browser model discovery so the prompt can be submitted without storing a provider credential; it does not claim a live model response. The script terminates its child process groups, removes its uniquely named Compose service and volume, verifies ownership of its script-created temporary root, and then removes that root when it exits.

For an interactive session, copy the working development defaults without editing them, start Postgres on the example's fixed `127.0.0.1:55439` port, migrate, and run Fastify/Vite on the example's fixed ports 3000/5173:

```bash
# from repo root, after `pnpm install`
cp apps/full-app/.env.example apps/full-app/.env # then fill in values
# bring up Postgres, then apply migrations:
cp apps/full-app/.env.example apps/full-app/.env
docker compose -f apps/full-app/docker-compose.dev.yml up -d --wait
pnpm --filter full-app migrate
pnpm --filter full-app dev
```

Open `http://localhost:5173`.
Open `http://localhost:5173/dev-login`. The `.env` defaults bind the backend and Vite to loopback, enable only the non-production dev-login helper, and intentionally leave mail unset so local accounts are not blocked on email verification. The helper also rejects non-loopback clients, including clients forwarded through the Vite dev proxy. Uncomment both mail values when testing verification flows. Stop Postgres with `docker compose -f apps/full-app/docker-compose.dev.yml down`; its named `postgres-data` volume persists for the next interactive run. Use `down --volumes` only when intentionally resetting local data. Override only the interactive Postgres host port with `BORING_DEV_POSTGRES_PORT`; the smoke always supplies an allocated value and removes its own uniquely named volume.

### Hosted automation scheduler

Expand All @@ -77,13 +86,15 @@ available as an operational fallback when the internal scheduler is enabled.

| Script | What it does |
|--------|--------------|
| `dev` | Build agent/workspace/core, then `tsx src/server/dev.ts` (Vite :5173 + Fastify) |
| `build` | Build packages, then `build-app.mts` (frontend → `dist/front`, server → `dist/server`) |
| `build:deps` | Topologically build the full-app dependency selector with bounded concurrency |
| `dev` | Build dependencies, load `.env` when present, then start Vite :5173 + Fastify |
| `build` | Build dependencies, then `build-app.mts` (frontend → `dist/front`, server → `dist/server`) |
| `start` | `node dist/server/main.js` (prod, listens on `PORT`) |
| `start:worker` | `node dist/server/agent-worker.js` — provider-neutral remote-worker process |
| `migrate` | `tsx src/server/migrate.ts` — apply DB migrations |
| `migrate` | Load `.env` when present, then apply core and automation DB migrations |
| `typecheck` / `lint` | `tsc --noEmit` (`lint` is an alias of `typecheck`) |
| `e2e` / `e2e:smoke` | Playwright against `e2e/playwright.config.ts` (the two scripts are identical) |
| `smoke:dev-console` | Zero-edit browser prompt proof using dynamically allocated loopback ports and `.env.example` defaults |
| `smoke:mcp-managed-agent` | `node --import tsx scripts/managed-agent-mcp-smoke.ts` — local stock MCP client smoke for `/mcp/managed-agent` |
| `smoke:remote-worker` | `node scripts/remote-worker-smoke.mjs` — local remote-worker contract/isolation smoke |

Expand Down Expand Up @@ -117,13 +128,12 @@ From `.env.example` and code. Required for a working server:
| `DATABASE_URL` | Postgres connection string |
| `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL` | Auth secret + base URL |
| `WORKSPACE_SETTINGS_ENCRYPTION_KEY` | 32-byte hex; encrypts per-workspace settings |
| `MAIL_FROM`, `MAIL_TRANSPORT_URL` | Mail transport (`console://` for dev) |

Common optional:

| Var | Default | Notes |
|-----|---------|-------|
| `PORT` / `HOST` / `LOG_LEVEL` | `3000` / `0.0.0.0` / `info` | HTTP server |
| `PORT` / `HOST` / `LOG_LEVEL` | `3000` / `0.0.0.0` / `info` | HTTP server. The local `.env.example` narrows `HOST` to `127.0.0.1`. |
| `CORS_ORIGINS` | `http://localhost:3000,http://localhost:5173` | Allowed origins |
| `BORING_PLUGIN_AUTHORING` | `0` | `1` installs the plugin-authoring surface |
| `BORING_AUTOMATION_INTERNAL_SCHEDULER` | `true` | Set to `false` only when an external scheduler owns hosted Automation wake-ups |
Expand All @@ -142,6 +152,10 @@ Common optional:
| `COMPOSIO_API_KEY` | — | Optional server-only managed connector credential resolved by the app's boring-mcp managed connector secret resolver. Do not create a `VITE_*` mirror. |
| `BORING_MCP_MAX_READONLY_INPUT_BYTES` | `65536` | Governed read-only MCP call input limit. |

### Agent fleet composition

Both full-app entrypoints pass `createFullAppAgentFleetComposition()` into `createCoreWorkspaceAgentServer`. That `agents` option uses the same configured-agent shape as workspace-playground: each entry has an `agentTypeId`, distinct `definition.instructions`, and its own encoded `model.preferred`, accompanied by `defaultAgentTypeId` and the app-owned `fleetCompiler`. Full-app currently configures `default` and `dummy`; use `BORING_AGENT_DEFAULT_MODEL` and `BORING_AGENT_DUMMY_MODEL` to override their preferred models. Host compatibility tools remain scoped into every addressed binding, while an app that wants per-agent plugin selection should list the preflighted plugin IDs in each agent's `plugins` bindings.

### Local dev login

For local development only, the dev server can expose a one-click login helper:
Expand All @@ -153,10 +167,10 @@ ENABLE_DEV_LOGIN=1 pnpm --filter full-app dev
Then open:

```txt
http://localhost:3000/dev-login
http://localhost:5173/dev-login
```

The route signs in `DEV_LOGIN_EMAIL` (default `[email protected]`) or creates it if missing, sets the normal Better Auth session cookie, and redirects to `/`. The core dev server proxies `/dev-login` from the frontend port to the API server. The route is unavailable unless `ENABLE_DEV_LOGIN=1` and is ignored in `NODE_ENV=production`.
The route signs in `DEV_LOGIN_EMAIL` (default `[email protected]`) or creates it if missing, sets the normal Better Auth session cookie, and redirects to `/`. Use the Vite URL above so the relative redirect lands on the frontend rather than the API-only development port. The core dev server proxies `/dev-login` to the API server while preserving the observed client address for the route's loopback-only check. The route rejects non-loopback clients, is unavailable unless `ENABLE_DEV_LOGIN=1`, and is ignored in `NODE_ENV=production`. Email verification follows ordinary mail configuration: the unedited development env leaves mail unset, while production and explicit mail-enabled testing retain the normal verification flow.

## Container reference

Expand Down
19 changes: 19 additions & 0 deletions apps/full-app/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: boring
POSTGRES_PASSWORD: boring
POSTGRES_DB: boring_ui_v2
ports:
- "127.0.0.1:${BORING_DEV_POSTGRES_PORT:-55439}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U boring -d boring_ui_v2"]
interval: 1s
timeout: 5s
retries: 30

volumes:
postgres-data:
3 changes: 2 additions & 1 deletion apps/full-app/e2e/google-auth-webserver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ cleanup() {
trap cleanup EXIT

printf '[features]\ngoogle_oauth = true\n' > "$CONFIG_PATH"
ln -s "$APP_DIR/node_modules" "$CONFIG_DIR/node_modules"

cd "$APP_DIR"
pnpm --filter @hachej/boring-core exec tsup --no-dts
pnpm --filter @hachej/boring-core exec sh -c "cp src/front/theme.css dist/front/theme.css"
pnpm migrate
pnpm build
cd "$CONFIG_DIR"
exec env NODE_ENV=production node "$APP_DIR/dist/server/main.js"
exec env NODE_ENV=production BORING_APP_CONFIG_PATH="$CONFIG_PATH" node "$APP_DIR/dist/server/main.js"
9 changes: 8 additions & 1 deletion apps/full-app/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@ const webServerEnv = Object.fromEntries(
MAIL_TRANSPORT_URL: mailTransportUrl,
PORT: String(apiPort),
CSP_ENABLED: 'true',
BORING_ALLOW_UNSAFE_AGENT_MODE: '1',
}).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),
)

export default defineConfig({
testDir: '.',
testMatch: ['smoke.spec.ts', 'csp.spec.ts', 'workspace-lifecycle.spec.ts', 'google-signup.spec.ts', 'runtime-readiness.spec.ts'],
testMatch: [
'smoke.spec.ts',
'csp.spec.ts',
'workspace-lifecycle.spec.ts',
'google-signup.spec.ts',
'runtime-readiness.spec.ts',
],
fullyParallel: false,
workers: 1,
retries: isCI ? 1 : 0,
Expand Down
Loading
Loading