Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
b406f0a
docs: capture frontend cache research
raphaeltm Aug 7, 2026
6f09122
perf(web): cache project data across responsive navigation
raphaeltm Aug 7, 2026
eadba8a
test(web): audit responsive cache behavior
raphaeltm Aug 7, 2026
74584d8
fix(web): isolate cached project data by user
raphaeltm Aug 7, 2026
93c1a1f
fix(web): keep project loading states truthful
raphaeltm Aug 8, 2026
9e2d865
refactor(web): configure project cache behavior
raphaeltm Aug 8, 2026
0170454
docs: finalize frontend cache validation
raphaeltm Aug 8, 2026
4254ba4
docs: archive frontend cache task
raphaeltm Aug 8, 2026
b71451d
task: add list triggers MCP tool
raphaeltm Aug 8, 2026
e67538b
task: activate list triggers MCP tool
raphaeltm Aug 8, 2026
a93e9c8
refactor(api): split MCP trigger handlers
raphaeltm Aug 8, 2026
ca52b36
feat(api): add MCP trigger listing
raphaeltm Aug 8, 2026
7294833
test(api): cover list triggers MCP contract
raphaeltm Aug 8, 2026
7e2f6ea
test(api): strengthen trigger listing validation
raphaeltm Aug 8, 2026
1e2d013
task: record list triggers validation
raphaeltm Aug 8, 2026
041cfad
task: archive list triggers MCP tool
raphaeltm Aug 8, 2026
1158d1d
refactor(api): share trigger ownership validation
raphaeltm Aug 8, 2026
3a6202b
docs(tasks): trace diagnostic incident correlation bug
raphaeltm Aug 9, 2026
fd1d1aa
fix: correlate diagnostic incidents with task lifecycle
raphaeltm Aug 9, 2026
916ad06
docs(tasks): link diagnostic correlation PR
raphaeltm Aug 9, 2026
fe7bf05
docs(tasks): record diagnostic correlation validation
raphaeltm Aug 9, 2026
c80919d
task: add Claude guided verification-code fix
raphaeltm Jul 26, 2026
64b7766
task: start Claude verification-code fix
raphaeltm Jul 26, 2026
83e675f
fix: complete Claude guided token setup
raphaeltm Jul 25, 2026
8af9062
fix: forward Claude verification code to sandbox CLI
raphaeltm Jul 26, 2026
08ca49d
fix: harden Claude setup exchange races and wrapping
raphaeltm Jul 26, 2026
204a3a2
fix: keep Claude exchange sessions uniquely active
raphaeltm Jul 26, 2026
98f1e08
fix(api): wire Claude verification path into driver entrypoint
raphaeltm Jul 26, 2026
c782f3c
fix(api): fail fast on rejected Claude verification codes
raphaeltm Jul 26, 2026
108392a
docs(task): archive Claude guided login fix
raphaeltm Jul 26, 2026
2b7e900
fix(api): submit Claude verification code as paste plus separate Enter
raphaeltm Jul 26, 2026
494ac8c
fix: classify Claude guided-login exchange failures and surface CLI d…
raphaeltm Jul 27, 2026
ae2dab2
docs(task): record real-code failure diagnosis and detail-capture fol…
raphaeltm Jul 27, 2026
b2bf8e0
fix: refresh Claude guided login after main drift
raphaeltm Aug 10, 2026
17dc056
fix: harden refreshed Claude guided login
raphaeltm Aug 10, 2026
fe5b43d
docs(tasks): plan scheduler lifecycle race lab
raphaeltm Aug 15, 2026
7418c21
docs(tasks): start scheduler lifecycle race lab
raphaeltm Aug 15, 2026
5a3a041
test(api): add deterministic scheduler lifecycle simulation
raphaeltm Aug 15, 2026
d8d782a
fix(api): make scheduler placement and cleanup atomic
raphaeltm Aug 15, 2026
d823982
test(vm-agent): expose missing project activity routing
raphaeltm Aug 15, 2026
3b10b03
fix(vm-agent): route activity by workspace project
raphaeltm Aug 15, 2026
95e0775
ci: explore scheduler lifecycles nightly
raphaeltm Aug 15, 2026
fe74505
test(api): repeat real D1 scheduler races
raphaeltm Aug 15, 2026
76089a8
test(api): support extended scheduler exploration
raphaeltm Aug 15, 2026
6bf907a
refactor(api): split workspace branch handling
raphaeltm Aug 15, 2026
130463e
fix(api): fail closed on scheduled teardown
raphaeltm Aug 15, 2026
599679c
fix(ci): resolve scheduler lifecycle findings
raphaeltm Aug 15, 2026
0819e51
docs(tasks): record scheduler security review
raphaeltm Aug 15, 2026
4071b03
Merge remote-tracking branch 'origin/main' into sam/fix-claude-code-g…
raphaeltm Aug 16, 2026
112259d
Merge remote-tracking branch 'origin/main' into sam/add-listtriggers-…
raphaeltm Aug 16, 2026
621c0ee
Merge origin/main into PR 1769
raphaeltm Aug 16, 2026
dabe751
fix(api): preserve Claude setup driver failure details
raphaeltm Aug 16, 2026
ca30aa0
test(web): assert auth cache cleanup composition
raphaeltm Aug 16, 2026
e6f2273
test(api): assert Claude verification Enter handoff
raphaeltm Aug 16, 2026
ccda368
fix(ci): avoid guided setup migration prefix collision
raphaeltm Aug 16, 2026
a458a1f
Merge remote-tracking branch 'origin/main' into sam/came-across-scree…
raphaeltm Aug 16, 2026
4f5a4b1
Avoid static fake secret matches in VM agent tests
raphaeltm Aug 16, 2026
bac2702
test(web): wait for profile wizard composer
raphaeltm Aug 16, 2026
f9b3c85
Reduce Sonar duplication in refresh helpers
raphaeltm Aug 16, 2026
4809d1e
Merge PR #1824 into batch 2 integration
raphaeltm Aug 16, 2026
fb5e71c
Merge PR #1779 into batch 2 integration
raphaeltm Aug 16, 2026
1aedea2
Merge PR #1770 into batch 2 integration
raphaeltm Aug 16, 2026
d7fb61d
Merge PR #1769 into batch 2 integration
raphaeltm Aug 16, 2026
c2f219a
Merge PR #1678 into batch 2 integration
raphaeltm Aug 16, 2026
7cddd52
fix: keep lifecycle failure shell neutral in batch integration
raphaeltm Aug 16, 2026
2ef6d22
Merge origin/main into batch 2 integration
raphaeltm Aug 16, 2026
680c526
fix(ci): renumber guided setup migration in batch integration
raphaeltm Aug 16, 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
24 changes: 24 additions & 0 deletions .claude/rules/23-cross-boundary-contract-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,30 @@ passes the same controls to child sessions or subagents. A runtime discriminator
such as an empty container ID must have a regression test that would fail if an
early return were moved back above the generated-config writer.

### Runtime Exit and Diagnostic Correlation Boundaries

Task lifecycle and diagnostic ingestion are also cross-service contracts. When a
runtime-owned exit can end an agent prompt or session, tests MUST prove the real
runtime path emits exactly one terminal callback and that the callback reaches
the control-plane task transition. Clearing local prompt state alone is not a
terminal outcome.

Intentional lifecycle writers such as user, parent-agent, or orchestrator stops
MUST use the canonical cancellation status, write the corresponding status
event, synchronize linked trigger executions, and run terminal cleanup. Test the
compare-and-set behavior so an intentional stop cannot overwrite a concurrent
fatal failure and hide the original cause.

When observability producers cannot supply task or session identifiers, start
the contract test with that least-correlated producer payload. Exercise the real
ingestion and enrichment boundary, then prove that:

- one authoritative candidate is enriched with its task and session identifiers;
- missing, cross-node, cross-session, stale, and ambiguous candidates remain
uncorrelated;
- retries may add previously missing correlation but cannot rebind an incident
to a different task or session.

### Why This Rule Exists

The R2 file upload feature shipped with two cross-boundary contract mismatches:
Expand Down
17 changes: 17 additions & 0 deletions .claude/rules/48-stale-while-revalidate-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,25 @@ modifying an existing one, use `useQuery`/`useMutation` instead of hand-rolled
- Use `queryClient.invalidateQueries(...)` after mutations instead of
`await reload()` chains threaded through context.
- Use `refetchInterval` instead of hand-rolled `setInterval` polls.
- Every authenticated query key must include the resolved user identity (or an
equivalent tenant/session namespace). Clear the previous namespace and gate
protected children while that identity changes so cached data from one
account can never render for another account, even for a single frame.

Hand-rolled loaders are only acceptable for genuinely non-query state
(WebSockets, streaming, imperative one-shots).

### 5. Responsive shells MUST preserve routed subtree identity

Changing between mobile and desktop chrome must not remount the routed page,
chat, composer, or media subtree. When breakpoint branches use different
sibling structures, give shared stateful slots stable keys (or keep one shared
slot outside the branches) so React can reconcile them across positions.

Every responsive shell change must include a portrait-to-landscape regression
test that crosses the actual breakpoint and proves local child state and mount
identity survive. A static test at one viewport is insufficient.

## Interaction-Effect Trace Requirement

When adding any state change that a `useEffect` in the same tree observes
Expand All @@ -123,3 +138,5 @@ Before committing UI data-fetching or context changes:
- [ ] Spinners gate only on "no data yet", never on "refetch in flight"
- [ ] Mutations invalidate/refresh data without unmounting visible content
- [ ] New fetch surfaces use TanStack Query (or document why not)
- [ ] Authenticated query keys are identity-scoped and account transitions are gated
- [ ] Breakpoint changes preserve routed and media subtree identity
21 changes: 21 additions & 0 deletions .claude/skills/env-reference/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ See `apps/api/.env.example` for the full list. Key variables:
- `DEPLOYMENT_RELEASE_RETENTION_LAST_RUN_KV_KEY` — KV interval marker (default: `cleanup:deployment-releases:last-run`)
- `COMPOSE_IMAGE_ARTIFACT_CLEANUP_BATCH_SIZE` — Maximum abandoned compose archives deleted per daily run (default: `250`)

### Guided Agent Credential Setup

- `MAX_CONCURRENT_SETUP_SESSIONS` — Concurrent Cloudflare Sandbox setup-session cap (default: `2`)
- `SETUP_SESSION_TTL_MS` — Setup-session lifetime before teardown (default: `900000`)
- `SETUP_SESSION_CAPTURE_POLL_MS` — Device-login and credential-capture poll interval (default: `3000`)
- `CODEX_DEVICE_AUTH_REQUEST_TIMEOUT_MS` — Codex app-server JSON-RPC request timeout (default: `30000`)
- `CLAUDE_SETUP_ENTER_DELAY_MS` — Delay before sending Enter as a separate stdin write after Claude's browser-displayed code is pasted into the CLI (default: `1000`)
- `CLAUDE_SETUP_EXCHANGE_TIMEOUT_MS` — Maximum wait for Claude's CLI exchange to finish after code submission (default: `120000`)
- `CLAUDE_SETUP_REJECTION_SETTLE_MS` — Wait for Ink redraws to settle before classifying the Claude CLI OAuth error line (default: `400`)
- `CLAUDE_SETUP_VERIFICATION_POLL_MS` — Poll interval for the browser-code handoff file inside the Claude setup sandbox (default: `500`)
- `CLAUDE_SETUP_TTY_COLUMNS` — PTY width used for `claude setup-token` to reduce opaque-token wrapping (default: `512`)
- `CLAUDE_SETUP_OUTPUT_BUFFER_BYTES` — Maximum in-memory Claude PTY output retained for parsing (default: `32768`)
- `CLAUDE_VERIFICATION_CODE_MAX_LENGTH` — Maximum accepted browser-displayed `code#state` length (default: `1024`)
- `CLAUDE_SETUP_ERROR_DETAIL_MAX_LENGTH` — Maximum sanitized Claude CLI diagnostic surfaced to the user (default: `160`)
- `CLAUDE_OAUTH_TOKEN_MAX_LENGTH` — Maximum captured Claude OAuth token length (default: `8192`)
- `SETUP_SESSION_SWEEP_MAX_CANDIDATES` — Maximum expired setup sessions torn down per sweep (default: `50`)
- `POOL_LEASE_BUFFER_MS` — Grace after the session TTL before a leaked setup-pool lease self-prunes (default: `300000`)

### Operational Control Loops

- `CRON_SWEEPS_ENABLED_KV_KEY` — Fail-open KV brake key for the five-minute operational sweep (default: `control-loops:cron-enabled`)
Expand Down Expand Up @@ -214,9 +232,12 @@ by the read-only cron-liveness check.
- `TASK_LIST_MAX_PAGE_SIZE` — Maximum task/project list page size
- `CHAT_SESSION_MESSAGE_LIMIT` — Default page size for chat session message REST responses when no limit is requested — used by the 3s poll and load-more (default: 500)
- `CHAT_SESSION_MESSAGE_MAX` — Ceiling any chat session message request is clamped to; the initial full-conversation load requests up to this (default: 50000)
- `MCP_TRIGGER_LIST_LIMIT` — Default result count for the `list_triggers` MCP tool (default: 20)
- `MCP_TRIGGER_LIST_MAX` — Maximum result count accepted by the `list_triggers` MCP tool (default: 100)

### Timeouts

- `ORCHESTRATOR_STOP_CAS_MAX_ATTEMPTS` — Maximum task-status compare-and-set attempts after a parent hard-stops a child runtime (default: 2)
- `TASK_CALLBACK_TIMEOUT_MS` — Timeout budget for delegated-task callback processing
- `TASK_CALLBACK_RETRY_MAX_ATTEMPTS` — Retry budget for delegated-task callback processing
- `TASK_RECONCILIATION_IDLE_MS` — Idle threshold before a visible task reconciliation check-in (default: 300000)
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/deploy-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,11 @@ jobs:
VITE_PUBLIC_WEBSITE_URL: ${{ vars.PUBLIC_WEBSITE_URL || '' }}
VITE_FEATURE_MULTI_TERMINAL: 'true'
VITE_DEBUG_DIAGNOSIS_EVENT_MAX_PAGES: ${{ vars.VITE_DEBUG_DIAGNOSIS_EVENT_MAX_PAGES || '100' }}
VITE_PROJECT_LIST_LIMIT: ${{ vars.VITE_PROJECT_LIST_LIMIT || '50' }}
VITE_PROJECT_POLL_INTERVAL_MS: ${{ vars.VITE_PROJECT_POLL_INTERVAL_MS || '30000' }}
VITE_SIDEBAR_PROJECT_POLL_INTERVAL_MS: ${{ vars.VITE_SIDEBAR_PROJECT_POLL_INTERVAL_MS || '60000' }}
VITE_PROJECT_PREFETCH_DELAY_MS: ${{ vars.VITE_PROJECT_PREFETCH_DELAY_MS || '120' }}
VITE_BACKGROUND_FETCH_DELAY_MS: ${{ vars.VITE_BACKGROUND_FETCH_DELAY_MS || '150' }}

# Bake the deployment-built vm-agent before Wrangler builds the raw container.
- name: Setup Go for Container Runtime
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/scheduler-lifecycle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Scheduler Lifecycle Exploration

on:
schedule:
- cron: '33 3 * * *'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: scheduler-lifecycle-${{ github.ref }}
cancel-in-progress: false

jobs:
explore:
name: Explore Scheduler Lifecycles
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts

- name: Build API dependencies
run: pnpm exec turbo run build --filter=@simple-agent-manager/api...

- name: Explore generated scheduler lifecycles
run: |
set -o pipefail
pnpm --filter @simple-agent-manager/api test:scheduler:nightly 2>&1 | tee scheduler-lifecycle.log

- name: Upload replay diagnostics
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: scheduler-lifecycle-replay-${{ github.run_id }}
path: scheduler-lifecycle.log
if-no-files-found: error
retention-days: 14
25 changes: 24 additions & 1 deletion apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,26 @@ BASE_DOMAIN=workspaces.example.com
# WEBHOOK_DELIVERY_MAX_PAGE_SIZE=100
# WEBHOOK_DELIVERY_PROCESSING_LEASE_SECONDS=300

# Guided agent credential setup via Cloudflare Sandbox
# MAX_CONCURRENT_SETUP_SESSIONS=2
# SETUP_SESSION_TTL_MS=900000
# SETUP_SESSION_CAPTURE_POLL_MS=3000
# CODEX_DEVICE_AUTH_REQUEST_TIMEOUT_MS=30000
# Claude Code v2.1.220 treats a large pasted code plus inline carriage return as
# text; keep Enter as a separate write after this settle delay.
# CLAUDE_SETUP_ENTER_DELAY_MS=1000
# CLAUDE_SETUP_EXCHANGE_TIMEOUT_MS=120000
# Wait for Ink redraw output to settle before classifying a mangled OAuth error.
# CLAUDE_SETUP_REJECTION_SETTLE_MS=400
# CLAUDE_SETUP_VERIFICATION_POLL_MS=500
# CLAUDE_SETUP_TTY_COLUMNS=512
# CLAUDE_SETUP_OUTPUT_BUFFER_BYTES=32768
# CLAUDE_VERIFICATION_CODE_MAX_LENGTH=1024
# CLAUDE_SETUP_ERROR_DETAIL_MAX_LENGTH=160
# CLAUDE_OAUTH_TOKEN_MAX_LENGTH=8192
# SETUP_SESSION_SWEEP_MAX_CANDIDATES=50
# POOL_LEASE_BUFFER_MS=300000

# NOTE: Hetzner tokens are NOT platform secrets.
# Users provide their own Hetzner API tokens through the Settings UI.
# These are stored encrypted (per-user) in the database.
Expand Down Expand Up @@ -532,13 +552,16 @@ INFOMANIAK_IP_POLL_INTERVAL_MS=3000
# ORCHESTRATOR_MAX_RETRIES_PER_TASK=3 # Max retry attempts per task via retry_subtask
# ORCHESTRATOR_DEPENDENCY_MAX_EDGES=50 # Max dependency edges per project via add_dependency
# ORCHESTRATOR_STOP_GRACE_MS=5000 # Grace period before hard stop after warning (ms)
# ORCHESTRATOR_STOP_CAS_MAX_ATTEMPTS=2 # Task-status CAS attempts after hard stop
# ORCHESTRATOR_MESSAGE_MAX_LENGTH=32768 # Max length for injected messages to child agents
# ORCHESTRATOR_ZERO_TASK_GRACE_MS=600000 # 10 minutes — allow tasks to land before terminalizing an empty mission
# ORCHESTRATOR_MAX_MISSION_LIFETIME_MS=86400000 # 24 hours — force terminal completion of a stuck mission

# MCP get_session_messages limits
# MCP list/read limits
# MCP_MESSAGE_LIST_LIMIT=50 # Default number of raw tokens fetched per request
# MCP_MESSAGE_LIST_MAX=200 # Max raw tokens per request (before grouping into logical messages)
# MCP_TRIGGER_LIST_LIMIT=20 # Default page size for list_triggers
# MCP_TRIGGER_LIST_MAX=100 # Max page size for list_triggers

# MCP idea management limits
# MCP_IDEA_CONTENT_MAX_LENGTH=65536 # Max length for idea content/description (64 KB)
Expand Down
2 changes: 2 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"build": "tsc",
"dev": "wrangler dev --port ${WRANGLER_PORT:-8787}",
"test": "vitest run",
"test:scheduler": "vitest run tests/simulation/scheduler-lifecycle-simulation.test.ts",
"test:scheduler:nightly": "SCHEDULER_SIM_PROFILE=nightly vitest run tests/simulation/scheduler-lifecycle-simulation.test.ts",
"test:debugging-workers": "vitest run --config vitest.debugging.workers.config.ts",
"test:workers": "vitest run --config vitest.workers.config.ts",
"test:watch": "vitest",
Expand Down
Loading
Loading