Live AI-driven adaptive UI for the Stackchain AI Lab Gitea experience.
Go to file
rockachopa e40c75b360
All checks were successful
CI / lint (push) Successful in 24s
Release / release-candidate (push) Successful in 4s
CI / build-frontend (push) Successful in 4s
Merge pull request 'Defer from mobile detail sheets and continue triage' (#257) from timmy/256-mobile-detail-defer into main
2026-08-08 03:17:03 +00:00
.gitea/workflows fix: use Gitea-compatible artifact upload 2026-08-04 14:59:22 +00:00
creative-deliverables Add creative deliverable for stackchain/stackchain-dashboard#5 2026-07-08 16:42:49 +00:00
docs feat: autonomous issue-to-release execution engine 2026-08-04 14:29:41 +00:00
frontend feat: defer from mobile detail sheets (#256) 2026-08-08 03:16:01 +00:00
release chore: release manifest and creative asset manifest 2026-07-13 13:48:38 +00:00
scripts ci: add automated CI/release workflows 2026-07-08 14:24:16 +00:00
src feat: deliver offline issue captures after app close (#250) 2026-08-08 01:44:20 +00:00
tests feat: defer from mobile detail sheets (#256) 2026-08-08 03:16:01 +00:00
.gitignore feat: persist authored action idempotency (#201) 2026-08-07 14:37:10 +00:00
README.md feat: add mobile Later queue (#254) 2026-08-08 02:41:09 +00:00
requirements.txt docs: add tested local quickstart for issue 24 2026-08-04 21:02:56 +00:00

stackchain-dashboard

Live AI-driven adaptive UI for the Stackchain AI Lab Gitea experience.

Local quickstart

Python 3.11 or newer is recommended. Create an isolated environment and install the pinned dependencies:

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt

Point the dashboard at the Gitea server root (without /api/v1) and provide a token that can read dashboard data, update the authenticated user's notification threads, create and self-assign issues, discover, claim, and release issue assignments, list repository labels and open milestones, set or clear due dates on assigned issues, create issue comments, close assigned issues, inspect/comment on assigned pull requests, merge assigned pull requests, and submit pull-request reviews. Pull-request replies and mobile My Work issue and PR comments use Gitea's issue-comment API; mobile issue capture requires issue creation and assignment permission. The New issue sheet can optionally select an open repository milestone and due date; the dashboard validates both and sends them with self-assignment in the single create request, so planned work appears in its release lane immediately. Issue capture and authored mobile actions (issue comments, pull-request comments, notification replies, and reviews) persist per-draft idempotency keys, so retrying after a timeout, reload, process restart, or handoff to another worker replays a confirmed result instead of posting duplicate content. Results are coordinated through a bounded SQLite ledger. Set STACKCHAIN_STATE_DIR to a persistent, writable service directory (or set STACKCHAIN_IDEMPOTENCY_DB to an explicit SQLite path); the local default is .stackchain-state/idempotency.sqlite3. Ledger reads and writes run outside the request event loop, and lock admission is bounded to 100 ms by default. Tune it with STACKCHAIN_IDEMPOTENCY_LOCK_TIMEOUT_SECONDS; keep the value below route deadlines. Reservation contention returns retryable HTTP 503 with Retry-After: 1. If contention occurs after the upstream mutation, the dashboard fails closed with Retry-After: 5 and asks the caller to verify the result before retrying. Direct API callers should preserve the Idempotency-Key header with the unchanged route and payload until a 201 response is confirmed. Closing an assigned issue, native Comment, Approve, and Request changes reviews, and assigned-PR merge require repository write permission. Native Comment, Approve, and Request changes reviews support head-scoped draft comments anchored to changed lines; the dashboard validates each comment path and submits the summary, decision, and inline comments in one review request. The dashboard rechecks the current pull-request head, CI success, draft state, and mergeability immediately before every merge. Serve the dashboard only to trusted users on its own origin; cross-origin API access is intentionally disabled. Then start the API and bundled frontend:

export GITEA_URL='https://forge.example.com'
export GITEA_TOKEN='<read-notification-and-issue-write-token>'
uvicorn src.main:app --host 127.0.0.1 --port 8000

Open http://127.0.0.1:8000/ for the dashboard. To verify the backend and its Gitea connection directly, request http://127.0.0.1:8000/api/v1/context; a successful response is JSON containing user, repos, issues, and pull_requests. Press Ctrl/Cmd+K in the dashboard to search commands plus issues and pull requests across every repository visible to the configured Gitea token. Remote search starts after two characters, is debounced, and keeps local commands usable if Gitea search is unavailable. Selecting a remote result opens a mobile-safe, read-only preview without discarding the search query; open unassigned issues can be claimed in place and handed into My Work after Gitea confirms the assignment. Closed work and pull requests remain read-only with a safe canonical Gitea link. The bounded APIs are available at GET /api/v1/search?q=<query>&limit=<1-25> and GET /api/v1/repos/<owner>/<repo>/issues/<number>/preview?kind=issue|pull. Never commit the token or place it in a tracked configuration file.

For service monitoring, GET /healthz is a liveness check that confirms the API process is running and does not contact Gitea. GET /readyz is the readiness check: it validates the configured Gitea credentials and returns HTTP 503 with an error when Gitea is unavailable or authentication fails.

The application-lifetime Gitea transport bounds aggregate upstream traffic and coalesces identical concurrent GETs without caching completed responses. By default, at most eight requests run at once, with one slot reserved for authored mutations so polling and detail-read bursts cannot starve comments, reviews, or other writes. Requests that cannot enter within 250 ms fail as retryable HTTP 503 responses. Tune these limits with GITEA_MAX_CONCURRENCY (minimum 2) and GITEA_ADMISSION_TIMEOUT_SECONDS (minimum 0.001); keep the admission timeout below the route deadlines. Streaming diff reads share the same read capacity, while POST, PATCH, PUT, and DELETE requests are never coalesced.

Offline mobile shell

At phone widths, a persistent bottom task dock keeps Work, Find, New, Search, and Drafts thumb-reachable. It reuses the existing sheets and My Work filter, preserves the selected release lane, shows the current draft count, respects the device safe area, and moves out of the way while a full-screen task is open. Desktop layout is unchanged.

My Work also has a local Later queue. Later today defers an item for four hours, while Tomorrow returns it at 09:00 in the device's local timezone. Deferred items leave normal and Attention queues without marking notifications read or changing any Gitea issue or pull request. They automatically return to their existing priority position at the wake time, and Bring back now restores them early. Later state is stored only in this browser, scoped to the confirmed Gitea login, and removed when fully loaded work confirms that an item no longer exists.

After one successful online load, the installed dashboard precaches a versioned, subpath-scoped application shell. During a network outage or a dashboard HTTP 500, 502, 503, or 504 response, navigation falls back to that shell when it is available so local issue and review drafts remain reachable. Authentication and other client-error responses are never hidden. A visible, accessible offline or server-outage notice distinguishes cached mode from live Gitea data, and the dashboard keeps polling until it can restore its live snapshot automatically.

Users can explicitly enable Keep My Work available offline. Each healthy live refresh then stores a seven-day, versioned snapshot containing only the signed-in user identity and queue-card metadata for issues, pull requests, unread updates, and pagination totals. Bodies, comments, diffs, credentials, repository catalogs, events, and complete API responses are excluded. A cold offline launch labels the saved time and renders this snapshot read-only; opening live details, pagination, and server mutations remain disabled until reconnection. Clear offline work data deletes the snapshot, and opting out deletes it automatically.

API responses and mutations are never cached by the service worker. New issue captures, issue comments, pull-request comments, and unread-update replies use bounded local outboxes when connectivity or a retryable server failure prevents delivery. Issue captures and authored messages are also mirrored into account-bound IndexedDB lanes and registered with Background Sync, so a supporting installed browser can deliver new issues, issue comments, pull-request comments, and unread-update replies after every dashboard client has closed. The worker verifies the current Gitea login, shares an atomic delivery claim with the foreground path, and preserves the original idempotency key. Browsers without IndexedDB or Background Sync keep the foreground reconnect behavior. Drafts shows queued and needs-attention messages with explicit send/discard controls; reopening the dashboard reconciles worker completions and permanent failures into the visible outbox. Foreground delivery flushes messages sequentially with their original idempotency keys. Tabs coordinate each queue through the browser lock manager (with an expiring local lease fallback), so an installed PWA and a browser tab cannot submit the same operation concurrently. Queue changes are broadcast to other tabs and refresh Drafts without polling; an abandoned lease can be reclaimed after expiry. State-sensitive actions such as reviews, merges, closures, labels, milestones, and assignments are never queued. Service-worker upgrades are atomic and remove only older stackchain-dashboard-* caches, preserving unrelated caches on the same origin.

Run the test suite with:

python3 -m pytest tests/ -q

Autonomous release worker

The deterministic issue-to-release engine lives at src/release_engine.py. It discovers or targets one Gitea issue, verifies its claim, creates an issue branch, invokes a configured coding agent, runs tests, pushes, and opens a linked pull request. Merge remains gated by CI/review; the existing release workflow drafts the release candidate after merge.

Plan against live Gitea without mutating anything:

python3 -m src.release_engine \
  --repo stackchain/stackchain-dashboard \
  --agent timmy \
  --issue 14 \
  --dry-run

Execute one ticket after implementing and committing its change directly on the deterministic branch printed by --dry-run:

export GITEA_TOKEN='<scoped-token>'
export RELEASE_AGENT_COMMAND=true
python3 -m src.release_engine \
  --repo stackchain/stackchain-dashboard \
  --agent timmy \
  --issue 19 \
  --test-command 'python3 -m pytest tests/ -q'

GITEA_TOKEN needs issue and repository write scopes. The engine verifies the claim, reruns the test command, pushes the branch, and opens a PR containing Closes #19 plus test evidence. Replace 19 with the selected issue number; do not run without --issue when processing a preselected ticket.

Durable state defaults to .release-engine/state.json. Full behavior and safety gates are documented in docs/release-engine-spec.md.