# Project export: Corvus Agent

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Corvus is a local-first, proof-carrying AI agent that builds software in isolated sandboxes, streams its work, verifies results, and returns inspectable evidence and screened artifacts for review.
- Devpost: https://devpost.com/software/corvus-agent
- GitHub: https://github.com/aGamingGod1234/corvus-platform
- Demo: https://corvus-platform-tau.vercel.app/
- Video: https://www.youtube.com/embed/qeuEyl9FPAc?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 6 GitHub contributor(s) — aGamingGod1234 (248 commits), Claude (27 commits), AlexanderMum (2 commits), asifdotpy (1 commits), chatgpt-codex-connector[bot] (1 commits), OpenAI Codex (1 commits)

## Devpost submission (written by the team)

### Inspiration

AI coding agents are becoming capable enough to change real projects, but the trust model is still weak: a polished answer can hide incomplete work, unsafe commands, leaked secrets, or changes made outside the intended workspace. We built Corvus around a different question: what if an agent had to carry proof of what it did? Corvus is a local-first, proof-carrying AI agent workspace. It gives people the speed of an autonomous coding agent while keeping execution bounded, evidence visible, and final publication under human control.

### What it does

Corvus turns a coding request into a supervised, inspectable run: Select a local project and an authenticated provider such as OpenAI Codex or Claude Code. Choose the model, thinking effort, and either Chat or Build mode. Review a server-authored safety preview that is cryptographically bound to the run configuration. Watch safe reasoning summaries, tool activity, and progress stream in real time. In Build mode, let the agent work inside a fresh isolated workspace rather than directly in the original checkout. Review the diff, test evidence, activity summary, detailed safety receipt, artifact hash, and secret-screening result. Download the screened project ZIP or explicitly prepare a branch and pull request for human review. Chat remains read-only. Build mode grants workspace-scoped write access while disabling user plugins, apps, and hooks by default. MCP servers are opt-in. Corvus never silently merges, force-pushes, or administers a repository. The interface adapts for Everyday or Developer users and Individual or Team workspaces without exposing every internal security primitive as configuration noise. The safety layer appears where it matters: before a run, while tools execute, when an action is blocked, and in the final receipt.

### How we built it

A single authoritative Python core powers the CLI and authenticated FastAPI service. A React and TypeScript client provides the responsive web experience, while a Tauri and Rust shell packages the same interface as a desktop app. Owner-scoped Server-Sent Events provide reconnect-safe streaming. Every run binds the provider identity, model, project scope, authorization snapshot, sandbox policy, network policy, tool permissions, MCP consent, and idempotency inputs. Fixed-argument adapters launch supported local CLIs without shell interpolation. Build work happens in a managed scratch workspace; resulting files are bounded, screened for secrets, packaged with a SHA-256 manifest, and returned with audit evidence. OpenAI Codex was both our primary engineering collaborator and a first-class local runtime inside Corvus. We used it for architecture, implementation, security review remediation, CI repair, UX iteration, and end-to-end verification. The product then detects the user's installed Codex CLI, validates the selected model and effort, streams the run, and preserves the final evidence.

### Challenges we ran into

The hardest problem was making safety real without making the product feel like a policy dashboard. We had to distinguish a genuinely failed run from an agent that completed its response but was waiting for confirmation, keep streaming responsive while hashing large workspaces, and make Windows workspace permissions compatible with a locked-down sandbox. Cross-platform packaging added another layer: the desktop app bundles a Python sidecar, React assets, and a Rust shell across Windows, macOS, and Linux. We also had to keep hosted-web claims honest: local mode hands off to the same-machine runtime, while cloud execution remains clearly labeled Preview until its E2B lifecycle is complete.

### Accomplishments we're proud of

A working local Build path that edits and tests code inside an isolated workspace and returns a downloadable, screened artifact. Safety previews and terminal receipts authored by the backend rather than trusted from the UI. Streaming model output, safe work summaries, resumable events, cancellation, and retry behavior. Real local provider discovery, model selection, thinking controls, custom rules, MCP consent, skills, schedules, and project workflows. A responsive desktop/web experience with adaptive user and workspace profiles. A large automated certification suite across Python, web, Rust, Windows, macOS, Linux, Docker, secret scanning, and SAST. A release workflow that only publishes checksummed installers from a reviewed commit already on main.

### What we learned

Security is most useful when it becomes understandable product feedback. “Protected Build,” a visible blocked-action explanation, and a final safety receipt communicate more than a long list of hidden controls. We also learned to treat completion as a verifiable state transition, not a confident sentence from a model.

### What's next

Next we plan to add production E2B cloud sandbox lifecycle management, durable provider/autonomy/budget/kill-switch repositories, production Google OAuth and cross-device continuity, richer team collaboration, signed/notarized installers, and additional Build-capable provider adapters. Those items remain explicit roadmap work rather than being presented as finished features today. Submission snapshot The source reviewed for this Build Week entry is PR #16 on branch codex/demo-readiness-fix. It was approved and merged as commit 4d0244d and published as v0.2.0-build-week.1, with checksummed Windows, macOS, and Linux x64 artifacts. That release is the judging snapshot; later development on main is outside this entry.

## README (from the GitHub repository)

# Corvus

<p align="center">
  <img src="apps/web/public/brand/corvus-lockup.svg" alt="Corvus" width="420" />
</p>

<p align="center">
  <a href="https://github.com/aGamingGod1234/corvus-platform/actions/workflows/certification.yml"><img alt="Certification" src="https://github.com/aGamingGod1234/corvus-platform/actions/workflows/certification.yml/badge.svg?branch=main" /></a>
  <a href="https://github.com/aGamingGod1234/corvus-platform/actions/workflows/security-scan.yml"><img alt="Security scan" src="https://github.com/aGamingGod1234/corvus-platform/actions/workflows/security-scan.yml/badge.svg?branch=main" /></a>
  <a href="https://github.com/aGamingGod1234/corvus-platform/releases"><img alt="Latest release" src="https://img.shields.io/github/v/release/aGamingGod1234/corvus-platform?include_prereleases" /></a>
</p>

> **Built with OpenAI Codex + GPT-5.6 Sol.** Codex was Corvus's primary engineering collaborator for the final product iteration and is also a first-class local coding runtime inside the product. See [Codex Usage](#codex-usage) for the implementation and verification details.

**Corvus is a local-first, proof-carrying AI agent workspace.** It lets an agent complete real coding work inside an isolated project workspace, then returns the diff, test evidence, safety receipt, and screened artifact for human review.

One authoritative Python core powers the CLI, FastAPI service, React client, and Tauri desktop shell. Shipped local paths reuse the same authorization, credential-reference, audit, and sandbox services; durable budget and kill-switch repositories remain explicit roadmap work.

## Evaluate Corvus in 90 seconds

1. Launch the desktop app and select a real project.
2. Choose an authenticated local provider, model, thinking level, and **Build** mode.
3. Ask Corvus to make a small change and watch safe progress stream in real time.
4. Review the changed files, test result, activity summary, and detailed safety receipt.
5. Export the screened ZIP or explicitly prepare a GitHub branch and pull request.

The rehearsable sub-three-minute journey is in [`docs/demo/BUILD_WEEK_DEMO.md`](docs/demo/BUILD_WEEK_DEMO.md). Verified commands and honest limitations are recorded in [`HACKATHON_STATUS.md`](HACKATHON_STATUS.md).

## What makes Corvus different

| Typical agent risk | Corvus approach |
| --- | --- |
| Work happens in an opaque environment | Every Build produces reviewable activity, evidence, and a terminal safety receipt |
| The agent edits the original checkout | Coding runs use a Corvus-owned isolated workspace pinned to the selected project |
| Permissions silently expand | Server-authored policy binds provider, model, filesystem, network, MCP, approval, and runtime choices |
| A successful-looking message is treated as proof | Completion is tied to observed changes, verification evidence, artifact screening, and hashes |
| One developer-shaped interface serves everyone | Everyday/Developer and Individual/Team profiles adapt language and navigation without changing authority |

Corvus never merges, force-pushes, transfers imported permissions, or lets a schedule publish code. Unsupported Cloud, billing, and provider paths remain visibly labeled **Preview** or unavailable.

## Capability status

| Capability | Status |
| --- | --- |
| Local Codex/Claude Chat and protected Build runs | **Working** |
| Streaming status, model controls, MCP consent, safety receipts, and artifact export | **Working** |
| Local projects, GitHub-assisted review flow, reviewed skills, and supervised schedules | **Working** |
| Everyday/Developer and Individual/Team-adapted application shell | **Working**; real multi-user Team authority is Preview |
| Google-backed hosted identity and device-continuity foundation | **Preview**; deployment configuration and production persistence required |
| E2B-backed Corvus Cloud execution | **Preview** — tracked in [#17](https://github.com/aGamingGod1234/corvus-platform/issues/17) |
| Production cross-device sync and team collaboration | **Roadmap** — tracked in [#18](https://github.com/aGamingGod1234/corvus-platform/issues/18) and [#19](https://github.com/aGamingGod1234/corvus-platform/issues/19) |
| Signed installers and secure automatic updates | **Roadmap** — tracked in [#20](https://github.com/aGamingGod1234/corvus-platform/issues/20) |

## Architecture at a glance

```mermaid
flowchart LR
    U["User"] --> C["React web or Tauri desktop"]
    C --> A["Authenticated FastAPI boundary"]
    A --> G["Authoritative governance core"]
    G --> R["Verified provider adapter"]
    R --> S["Isolated project workspace"]
    S --> E["Diff, tests, screened artifact"]
    G --> D["Durable events and audit receipts"]
    E --> C
    D --> C
```

## A workspace that fits the user

Corvus adapts its language and navigation without creating separate products or separate security rules.

| Work style | Personal workspace | Team workspace preview |
| --- | --- | --- |
| Everyday | Home, My Work, Automations, Files | Team Home, Assigned Work, Approvals, Knowledge, People |
| Developer | Repositories, Threads, Changes, Runs, Skills | Repositories, Work Queue, Reviews, Environments, Policies |

The Team profile currently previews the shared-work information architecture. It does not manufacture members, permissions, or authority before the real collaboration capability is connected.

## Choose where Corvus runs

- **On this computer:** operational today. The desktop app supervises the same-machine sidecar, and the browser client can connect to the same local service.
- **Corvus Cloud (E2B):** clearly labeled **Preview**. The current build does not create a cloud sandbox, perform Google sign-in, collect payment, or imply that those paths are available.

Local and future Cloud runtimes share contracts; clients never grant themselves workspace authority.

## What works today

- Durable outcomes, dependency-linked workflows, attempts, leases, checkpoints, artifacts, lineage, conversations, and resumable event streams.
- One-time approvals, deterministic effect idempotency, budget reservation and settlement, kill switches, and restart recovery.
- Connected CLI, FastAPI, generated TypeScript client, React web app, and Tauri Windows shell over the same application services.
- Local/demo collaboration, governed memory, versioned skills and routines, signed offline intents, and signed channel ingress.
- Real local repository registration and GitHub status through fixed-argument Git and `gh` adapters that never store a GitHub token.
- Durable Codex runs in managed Git worktrees, with reviewable diffs, bounded evidence, real secret scanning, cancellation, retry, recovery, and explicit discard.
- Confirmed branch, commit, push, and draft/ready pull-request publication without merge, force-push, or repository-administration authority.
- Reviewed cross-agent skill import from Codex, Claude Code, Hermes, Copilot, and portable Agent Skills locations, with immutable versions and quarantine scanning.
- Timezone-aware local schedules that create ordinary supervised runs and stop code-changing output before push or pull-request creation.
- Optional tray/background operation, launch at login, and redacted native run notifications in the installed desktop app.
- Adaptive Everyday/Developer and Personal/Team workspace profiles with responsive desktop and mobile navigation.
- A security-focused agent-runtime foundation with immutable requests, provider-binding digests, verified authority receipts, bounded autonomy proofs, fail-closed capability discovery, redacted hash-chained events, replay resistance, and explicit audit-pending results.
- A chat-first local agent workspace with on-demand history, provider/model/thinking controls, safe streamed reasoning summaries and work status, explicit MCP opt-in, and downloadable project artifacts.
- Server-authored safety previews bind every Build confirmation to the exact runtime policy digest; completed builds return a

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 398 recognized source files, 5334 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Rust (language) — detected in the code
- TypeScript (language) — detected in the code
- Docker (technology) — claimed on Devpost, not found in the code
- Vercel (technology) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (120 of 435)

```
.dockerignore
.env.example
.gitattributes
.github/CODEOWNERS
.github/GUARDRAIL_CHECKLIST.md
.github/THREAT_MODEL.md
.github/workflows/certification.yml
.github/workflows/desktop-release.yml
.github/workflows/security-scan.yml
.gitignore
.hermes/plans/corvus-milestone-0-5.md
.hermes/plans/m005-review-fixes.md
.python-version
.superpowers/sdd/fasttrack-frontend-report.md
.superpowers/sdd/task-2.1-report.md
.superpowers/sdd/task-2.2-report.md
apps/desktop/package.json
apps/desktop/README.md
apps/desktop/src-tauri/build.rs
apps/desktop/src-tauri/capabilities/default.json
apps/desktop/src-tauri/Cargo.lock
apps/desktop/src-tauri/Cargo.toml
apps/desktop/src-tauri/icons/icon.icns
apps/desktop/src-tauri/permissions/autogenerated/get_background_mode.toml
apps/desktop/src-tauri/permissions/autogenerated/load_desktop_preferences.toml
apps/desktop/src-tauri/permissions/autogenerated/open_external_url.toml
apps/desktop/src-tauri/permissions/autogenerated/save_artifact_file.toml
apps/desktop/src-tauri/permissions/autogenerated/save_desktop_preferences.toml
apps/desktop/src-tauri/permissions/autogenerated/select_repository_directory.toml
apps/desktop/src-tauri/permissions/autogenerated/set_background_mode.toml
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src-tauri/src/main.rs
apps/desktop/src-tauri/tauri.conf.json
apps/desktop/src-tauri/tauri.release.conf.json
apps/web/api/corvus-v2.ts
apps/web/api/v2/[...path].ts
apps/web/HOSTED_RUNTIME_SECURITY.md
apps/web/index.html
apps/web/package.json
apps/web/pnpm-workspace.yaml
apps/web/src/api.test.ts
apps/web/src/api.ts
apps/web/src/App.test.tsx
apps/web/src/App.tsx
apps/web/src/App.workspace.test.tsx
apps/web/src/app/AppShell.test.tsx
apps/web/src/app/AppShell.tsx
apps/web/src/app/artifactDownload.test.ts
apps/web/src/app/artifactDownload.ts
apps/web/src/app/BackgroundRunNotifier.test.tsx
apps/web/src/app/BackgroundRunNotifier.tsx
apps/web/src/app/ContributionPanel.test.tsx
apps/web/src/app/ContributionPanel.tsx
apps/web/src/app/conversationApi.test.ts
apps/web/src/app/conversationApi.ts
apps/web/src/app/conversationStorage.test.ts
apps/web/src/app/conversationStorage.ts
apps/web/src/app/ConversationWorkspace.test.tsx
apps/web/src/app/ConversationWorkspace.tsx
apps/web/src/app/desktopPreferences.test.ts
apps/web/src/app/desktopPreferences.ts
apps/web/src/app/devicePreferences.test.ts
apps/web/src/app/devicePreferences.ts
apps/web/src/app/externalAuth.test.ts
apps/web/src/app/externalAuth.ts
apps/web/src/app/featureFeedback.test.ts
apps/web/src/app/featureFeedback.ts
apps/web/src/app/LocalFirstRunFlow.test.tsx
apps/web/src/app/LocalFirstRunFlow.tsx
apps/web/src/app/OnboardingFlow.test.tsx
apps/web/src/app/OnboardingFlow.tsx
apps/web/src/app/PortableSkillsWorkspace.test.tsx
apps/web/src/app/PortableSkillsWorkspace.tsx
apps/web/src/app/preferences.test.ts
apps/web/src/app/preferences.ts
apps/web/src/app/providerDefaults.ts
apps/web/src/app/RepositoriesWorkspace.test.tsx
apps/web/src/app/RepositoriesWorkspace.tsx
apps/web/src/app/RoutinesWorkspace.test.tsx
apps/web/src/app/RoutinesWorkspace.tsx
apps/web/src/app/RunsWorkspace.test.tsx
apps/web/src/app/RunsWorkspace.tsx
apps/web/src/app/SchedulesWorkspace.test.tsx
apps/web/src/app/SchedulesWorkspace.tsx
apps/web/src/app/SettingsPanel.test.tsx
apps/web/src/app/SettingsPanel.tsx
apps/web/src/app/WorkspaceErrorBoundary.test.tsx
apps/web/src/app/WorkspaceErrorBoundary.tsx
apps/web/src/app/workspaceProfiles.test.ts
apps/web/src/app/workspaceProfiles.ts
apps/web/src/app/WorkspaceRouter.test.tsx
apps/web/src/app/WorkspaceRouter.tsx
apps/web/src/auth/authApi.test.ts
apps/web/src/auth/authApi.ts
apps/web/src/auth/AuthProvider.test.tsx
apps/web/src/auth/AuthProvider.tsx
apps/web/src/components/Brand.test.tsx
apps/web/src/components/Brand.tsx
apps/web/src/components/ConnectionBanner.tsx
apps/web/src/components/dialogFocus.ts
apps/web/src/components/NavigationRail.test.tsx
apps/web/src/components/NavigationRail.tsx
apps/web/src/components/ResponsiveNavigation.test.tsx
apps/web/src/components/ResponsiveNavigation.tsx
apps/web/src/components/SyncConflictPanel.test.tsx
apps/web/src/components/SyncConflictPanel.tsx
apps/web/src/components/WorkspaceSwitcher.test.tsx
apps/web/src/components/WorkspaceSwitcher.tsx
apps/web/src/designSystem.test.js
apps/web/src/generated/api.ts
apps/web/src/icons.tsx
apps/web/src/main.tsx
apps/web/src/PlatformApp.test.tsx
apps/web/src/PlatformApp.tsx
apps/web/src/runtime/CloudPreview.tsx
apps/web/src/runtime/localRuntime.test.ts
apps/web/src/runtime/localRuntime.ts
apps/web/src/runtime/LocalRuntimeLauncher.tsx
apps/web/src/styles.css
apps/web/src/styles/adaptive-shell.css
[315 more files omitted for size]
```

### Dependencies

- apps/desktop/package.json: @tauri-apps/cli@2.11.4
- apps/desktop/src-tauri/Cargo.toml: hmac@=0.12.1, rand@=0.9.2, sha2@=0.10.9, tauri@=2.11.5, tauri-build@=2.6.3, tauri-plugin-autostart@=2.5.1, tauri-plugin-dialog@=2.7.1, tauri-plugin-notification@=2.3.3, tauri-plugin-single-instance@=2.4.3
- apps/web/package.json: @fontsource-variable/fraunces@^5.2.8, @fontsource-variable/inter-tight@^5.2.7, @fontsource/ibm-plex-mono@^5.2.6, @tauri-apps/api@2.11.1, @tauri-apps/plugin-autostart@2.5.1, @tauri-apps/plugin-notification@2.3.3, @testing-library/jest-dom@^6.6.4, @testing-library/react@^16.3.0, @testing-library/user-event@^14.6.1, @types/react@^19.1.10, @types/react-dom@^19.1.7, @vitejs/plugin-react@^5.0.2, jsdom@^26.1.0, openapi-fetch@^0.15.0, openapi-typescript@^7.9.1, react@^19.1.1, react-dom@^19.1.1, react-markdown@^10.1.0, rehype-sanitize@^6.0.0, remark-gfm@^4.0.1, typescript@^5.9.2, vite@^7.1.5, vitest@^3.2.4
- pyproject.toml: alembic@>=1.14,<2, authlib@>=1.6,<2, cryptography@>=48.0.1,<49, docker@>=7,<8, fastapi@>=0.116,<1, httpcore@>=1,<2, httpx@>=0.28,<1, keyring@>=25,<26, platformdirs@>=4,<5, psycopg[binary]@>=3.2,<4, pydantic@>=2.10,<3, pyyaml@>=6,<7, rich@>=13.9,<15, sqlalchemy@>=2,<3, textual@>=1,<7, typer@>=0.15,<1, uvicorn@>=0.35,<1

### Recent commits (newest first)

- docs: highlight Codex and GPT-5.6 usage (#21)
- chore(release): freeze Build Week 2026 submission
- Merge pull request #12 from aGamingGod1234/codex/beta-0.2.0-beta.2
- fix(runs): stabilize evidence pagination
- docs(deploy): record production OAuth verification
- fix(security): avoid predictable hosted temp database
- fix(database): support long revisions on PostgreSQL
- fix(deploy): add secure hosted ASGI entry point
- fix(deploy): preserve backend wheel filename
- chore(deploy): add focused Railway backend image
- docs(auth): record GitHub consent boundary
- fix(audit): preserve evidence insertion order
- fix(ci): guard Win32 ctypes imports
- style(ci): format beta runtime tests
- test(ci): bound ACL concurrency fixture
- test(ci): normalize profile boundaries cross-platform
- fix(security): serialize desktop ACL updates
- test(ci): stabilize concurrent ACL assertions
- Merge remote-tracking branch 'origin/main' into codex/beta-0.2.0-beta.2
- fix(desktop): harden local runtime interactions

## Key source files (fetched from GitHub, selected and truncated for size)

### LICENSE.md

```markdown
# Proprietary License

Copyright (c) 2026 Lucas / aGamingGod1234. All rights reserved.

This source code and the accompanying Corvus software, documentation, designs,
and assets are proprietary. No permission is granted to copy, modify,
distribute, sublicense, sell, or create derivative works from this material
without prior written permission from the copyright holder.

The repository may be viewed and evaluated for the hackathon and for code
review. That limited access does not grant a license to reuse the material.

Third-party components remain subject to their respective licenses.

```

### DESIGN.md

```markdown
# Corvus Visual System

## Theme

Corvus is used on a developer's desktop during focused work, often in a dim environment. Dark mode is the primary demo surface, with an equally functional light mode.

## Color

Use a restrained palette of slightly blue-tinted neutrals with cyan reserved for primary actions, current selection, and verified information. The central work surface is the darkest layer; the navigation sidebar is one step lighter. Error, warning, and success states use distinct semantic colors plus text or icons.

## Typography

Use Inter Tight for interface text and IBM Plex Mono for identifiers and machine state. Fraunces is limited to rare editorial moments outside dense product controls; product-page headings use the interface family with compact fixed sizing.

## Layout

Use a fixed desktop app shell that fits the viewport. The shell itself never scrolls; only the active content region or deliberately scrollable transcript/list may scroll. Settings replaces the application navigation with its own category sidebar and a clear Back to app action.

## Components

Controls use a consistent 7px radius, visible focus rings, restrained borders, and explicit disabled/loading/error states. Lists and tables are preferred for repositories, runs, schedules, and skills. Empty states include one clear next action when the action is available.

## Motion

Keep state transitions between 150 and 220ms with ease-out timing. Respect reduced motion. Do not animate layout or add decorative page-load sequences.

```

### Dockerfile

```
# syntax=docker/dockerfile:1.7
FROM node:22.17.0-bookworm-slim AS web-builder
WORKDIR /src/apps/web
RUN corepack enable && corepack prepare pnpm@11.13.0 --activate
COPY apps/web/package.json apps/web/pnpm-lock.yaml apps/web/pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile
COPY apps/web/ ./
RUN pnpm build

FROM python:3.12.10-slim-bookworm AS wheel-builder
WORKDIR /src
RUN python -m pip install --no-cache-dir build==1.3.0
COPY pyproject.toml README.md ./
COPY corvus/ corvus/
RUN python -m build --wheel --outdir /wheel

FROM python:3.12.10-slim-bookworm AS runtime
ENV CORVUS_BOOTSTRAP_TOKEN="" \
    CORVUS_SESSION_SECRET="" \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1
RUN useradd --system --uid 10001 --home-dir /app --create-home corvus \
    && install -d -o corvus -g corvus /data /app/web
COPY --from=wheel-builder /wheel/*.whl /tmp/corvus.whl
RUN python -m pip install --no-cache-dir /tmp/corvus.whl && rm /tmp/corvus.whl
COPY --from=web-builder --chown=corvus:corvus /src/apps/web/dist/ /app/web/
USER corvus
WORKDIR /app
EXPOSE 8080
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s --retries=3 \
  CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/ready', timeout=2).read()"]
CMD ["corvus-mvp", "server", "--database", "/data/corvus.sqlite3", "--host", "0.0.0.0", "--port", "8080", "--static-web-dir", "/app/web"]

```

### pyproject.toml

```
[build-system]
requires = ["hatchling>=1.27,<2"]
build-backend = "hatchling.build"

[project]
name = "corvus"
version = "0.2.0a1"
description = "Configuration-driven, proof-carrying AI development platform"
readme = "README.md"
requires-python = ">=3.12,<3.14"
license = { text = "Proprietary" }
authors = [{ name = "Corvus" }]
dependencies = [
  "alembic>=1.14,<2",
  "authlib>=1.6,<2",
  "cryptography>=48.0.1,<49",
  "docker>=7,<8",
  "fastapi>=0.116,<1",
  "httpcore>=1,<2",
  "httpx>=0.28,<1",
  "keyring>=25,<26",
  "platformdirs>=4,<5",
  "psycopg[binary]>=3.2,<4",
  "pydantic>=2.10,<3",
  "pyyaml>=6,<7",
  "rich>=13.9,<15",
  "sqlalchemy>=2,<3",
  "textual>=1,<7",
  "typer>=0.15,<1",
  "uvicorn>=0.35,<1",
]

[project.scripts]
corvus = "corvus.cli:app"
corvus-mvp = "corvus.mvp.cli:mvp_app"

[dependency-groups]
dev = [
  "bandit>=1.8,<2",
  "httpx2>=2.6.0",
  "mypy>=1.15,<2",
  "pip-audit>=2.9,<3",
  "pytest>=9.0.3,<10",
  "pytest-asyncio>=0.25,<2",
  "ruff>=0.12,<1",
  "types-docker>=7,<8",
  "types-pyyaml>=6,<7",
]

[tool.hatch.build.targets.wheel]
packages = ["corvus"]

[tool.pytest.ini_options]
minversion = "8.3"
testpaths = ["tests"]
addopts = ["-ra", "--strict-markers", "--basetemp=.pytest-tmp"]

[tool.ruff]
target-version = "py312"
line-length = 100
extend-exclude = [".pytest-tmp", ".pytest-*"]

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "UP", "B", "S"]
ignore = ["S101"]

[tool.ruff.lint.isort]
known-first-party = ["corvus"]

[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"]

[tool.mypy]
python_version = "3.12"
strict = true
packages = ["corvus"]

```

### apps/desktop/package.json

```
{
  "name": "@corvus/desktop",
  "private": true,
  "version": "0.2.0-build-week.1",
  "scripts": {
    "tauri": "tauri",
    "check": "tauri build --no-bundle"
  },
  "devDependencies": {
    "@tauri-apps/cli": "2.11.4"
  }
}

```

### apps/web/package.json

```
{
  "name": "@corvus/web",
  "private": true,
  "version": "0.2.0-build-week.1",
  "type": "module",
  "scripts": {
    "dev": "vite --host 0.0.0.0",
    "build": "tsc -b && vite build",
    "test": "vitest run",
    "generate:api": "openapi-typescript ../../openapi/corvus-mvp.json -o src/generated/api.ts"
  },
  "dependencies": {
    "@fontsource-variable/fraunces": "^5.2.8",
    "@fontsource-variable/inter-tight": "^5.2.7",
    "@fontsource/ibm-plex-mono": "^5.2.6",
    "@tauri-apps/api": "2.11.1",
    "@tauri-apps/plugin-autostart": "2.5.1",
    "@tauri-apps/plugin-notification": "2.3.3",
    "openapi-fetch": "^0.15.0",
    "react": "^19.1.1",
    "react-dom": "^19.1.1",
    "react-markdown": "^10.1.0",
    "rehype-sanitize": "^6.0.0",
    "remark-gfm": "^4.0.1"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^6.6.4",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^14.6.1",
    "@types/react": "^19.1.10",
    "@types/react-dom": "^19.1.7",
    "@vitejs/plugin-react": "^5.0.2",
    "jsdom": "^26.1.0",
    "openapi-typescript": "^7.9.1",
    "typescript": "^5.9.2",
    "vite": "^7.1.5",
    "vitest": "^3.2.4"
  }
}

```

### apps/desktop/src-tauri/Cargo.toml

```
[package]
name = "corvus-desktop"
version = "0.2.0-build-week.1"
description = "Supervised desktop shell for the Corvus hackathon MVP"
edition = "2024"
rust-version = "1.85"

[lib]
name = "corvus_desktop"
crate-type = ["lib"]

[[bin]]
name = "corvus-desktop"
path = "src/main.rs"

[build-dependencies]
tauri-build = { version = "=2.6.3", features = [] }

[dependencies]
hmac = "=0.12.1"
rand = "=0.9.2"
sha2 = "=0.10.9"
tauri = { version = "=2.11.5", features = ["tray-icon"] }
tauri-plugin-autostart = "=2.5.1"
tauri-plugin-dialog = "=2.7.1"
tauri-plugin-notification = "=2.3.3"
tauri-plugin-single-instance = "=2.4.3"

```

### corvus/cli.py

```python
from __future__ import annotations

import asyncio
import json
import os
import sys
from collections.abc import Callable
from dataclasses import dataclass
from enum import StrEnum
from pathlib import Path
from typing import Annotated, Literal
from uuid import UUID, uuid4

import keyring
import typer
from cryptography.fernet import Fernet
from keyring.errors import KeyringError
from rich.console import Console
from rich.table import Table

from corvus import __version__
from corvus.chat_agent import ChatAgent
from corvus.codex_cli import CodexCliProvider, CodexCliService
from corvus.codex_install import CodexCliInstaller, CodexInstallError
from corvus.config import ConfigManager, CorvusPaths
from corvus.delivery import DeliveryError, DeliveryManager
from corvus.evals import run_eval
from corvus.memory import MemoryManager
from corvus.models import MemoryRecord, ModelProvider, RunPhase
from corvus.onboarding import OnboardingChoices, OnboardingError, OnboardingManager
from corvus.onboarding_tui import FirstRunApp
from corvus.orchestration import AgentOrchestrator
from corvus.provider_control import ConfiguredLiveModelController
from corvus.providers import HttpProvider, ModelProviderClient
from corvus.sandbox import (
    DEVELOPMENT_SANDBOX_IMAGE,
    PRODUCTION_SANDBOX_IMAGE,
    DockerSandbox,
    PodmanSandbox,
    SandboxError,
    validate_sandbox_image,
)
from corvus.skills import SkillRegistry
from corvus.store import TraceStore
from corvus.tui import CorvusApp
from corvus.workflow import CodingWorkflow, SandboxBackend

app = typer.Typer(no_args_is_help=False, help="Corvus trusted coding agent")
model_app = typer.Typer(help="Configure model providers")
memory_app = typer.Typer(help="Inspect and control project memory")
skills_app = typer.Typer(help="Inspect and control versioned skills")
app.add_typer(model_app, name="model")
app.add_typer(memory_app, name="memory")
app.add_typer(skills_app, name="skills")
console = Console(stderr=False)


class SandboxOption(StrEnum):
    """User-selectable sandbox routes; ``none`` is deliberately chat-only."""

    AUTO = "auto"
    DOCKER = "docker"
    PODMAN = "podman"
    NONE = "none"


SandboxFactory = Callable[[], SandboxBackend]


@dataclass(frozen=True)
class SandboxRuntime:
    requested: SandboxOption
    backend: Literal["docker", "podman", "none"]
    factory: SandboxFactory | None
    detail: str

    @property
    def available(self) -> bool:
        return self.factory is not None


def resolve_sandbox_runtime(
    requested: SandboxOption | str,
    *,
    image: str | None = None,
    production: bool = True,
    docker_status: tuple[bool, str] | None = None,
    podman_status: tuple[bool, str] | None = None,
) -> SandboxRuntime:
    """Resolve one explicit or automatic route without ever falling back to host execution."""

    selection = requested if isinstance(requested, SandboxOption) else SandboxOption(requested)
    if selection is SandboxOption.NONE:
        return SandboxRuntime(
            requested=selection,
            backend="none",
            factory=None,
            detail=(
                "Chat-only mode selected; ordinary chat is available and isolated /build is "
                "disabled."
            ),
        )
    selected_image = image or (
        PRODUCTION_SANDBOX_IMAGE if production else DEVELOPMENT_SANDBOX_IMAGE
    )
    try:
        validate_sandbox_image(selected_image, production=production)
    except SandboxError as exc:
        return SandboxRuntime(
            requested=selection,
            backend="none",
            factory=None,
            detail=f"Isolated /build is disabled: {exc}.",
        )
    docker_ok, docker_detail = docker_status or DockerSandbox.available()
    podman_ok, podman_detail = podman_status or PodmanSandbox.available()
    if selection is SandboxOption.DOCKER:
        return SandboxRuntime(
            requested=selection,
            backend="docker" if docker_ok else "none",
            factory=(lambda: DockerSandbox(image=selected_image, production=production))
            if docker_ok
            else None,
            detail=(
                f"Docker {docker_detail}"
                if docker_ok
                else f"Docker was selected but is unavailable. {docker_detail}"
            ),
        )
    if selection is SandboxOption.PODMAN:
        return SandboxRuntime(
            requested=selection,
            backend="podman" if podman_ok else "none",
            factory=(lambda: PodmanSandbox(image=selected_image, production=production))
            if podman_ok
            else None,
            detail=(
                f"Podman {podman_detail}"
                if podman_ok
                else f"Podman was selected but is unavailable. {podman_detail}"
            ),
        )
    if docker_ok:
        return SandboxRuntime(
            requested=selection,
            backend="docker",
            factory=lambda: DockerSandbox(image=selected_image, production=production),
            detail=f"Auto selected Docker {docker_detail}",
        )
    if podman_ok:
        return SandboxRuntime(
            requested=selection,
            backend="podman",
            factory=lambda: PodmanSandbox(image=selected_image, production=production),
            detail=f"Auto selected Podman {podman_detail}",
        )
    return SandboxRuntime(
        requested=selection,
        backend="none",
        factory=None,
        detail=(
            "No supported sandbox engine is available. "
            f"Docker: {docker_detail} Podman: {podman_detail} "
            "Ordinary chat remains available; isolated /build is disabled."
        ),
    )


def configured_sandbox_image() -> str | None:
    image = os.environ.get("CORVUS_SANDBOX_IMAGE", "").strip()
    return image or None


def configured_sandbox_option(paths: CorvusPaths) -> SandboxOption:
    """Load the persisted onboarding choice, defaulting safely to auto on corrupt state."""

    try:
        sel
[truncated — 32780 more characters]
```

### corvus/mvp/cli.py

```python
from __future__ import annotations

import json
import secrets
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import Annotated, Any

import typer
import uvicorn
from fastapi import FastAPI
from pydantic import ValidationError

from corvus.mvp.api import create_app
from corvus.mvp.core import CorvusService, DomainConflict, DomainNotFound
from corvus.mvp.deployment import DeploymentSettings
from corvus.mvp.governance import GovernanceService, LocalSecretBroker
from corvus.mvp.ingress import ChannelIngressService, LocalEnvelopeSigner, OfflineConnectorService
from corvus.mvp.models import EffectBinding, WorkItemDefinition

mvp_app = typer.Typer(help="Run the local Corvus M2-M11 hackathon MVP")
project_app = typer.Typer(help="Create and inspect MVP projects")
outcome_app = typer.Typer(help="Create versioned outcome contracts")
workflow_app = typer.Typer(help="Create and control durable workflows")
mvp_app.add_typer(project_app, name="project")
mvp_app.add_typer(outcome_app, name="outcome")
mvp_app.add_typer(workflow_app, name="workflow")

DatabaseOption = Annotated[Path, typer.Option("--database", help="MVP SQLite database")]
JsonOption = Annotated[bool, typer.Option("--json", help="Emit machine-readable JSON")]

DEFAULT_SERVER_HOST = "127.0.0.1"
DEFAULT_SERVER_PORT = 8080
LOOPBACK_SERVER_HOSTS = frozenset({"127.0.0.1", "localhost", "::1"})
DEFAULT_PAIRING_REFERENCE = "env://CORVUS_BOOTSTRAP_TOKEN"
DEFAULT_SIGNING_REFERENCE = "env://CORVUS_SESSION_SECRET"
DEFAULT_INSTANCE_REFERENCE = "env://CORVUS_INSTANCE_TOKEN"
MINIMUM_SESSION_SECRET_BYTES = 32


def _service(database: Path) -> CorvusService:
    return CorvusService.open(database.expanduser().resolve())


def build_server_app(
    *,
    database: Path,
    pairing_ref: str,
    signing_ref: str,
    static_web_dir: Path | None = None,
    allowed_origins: frozenset[str] | None = None,
    allow_existing_user_pairing: bool = False,
    instance_ref: str | None = None,
) -> FastAPI:
    """Build the loopback API without retaining plaintext credentials in configuration."""
    broker = LocalSecretBroker()
    bootstrap_token = broker.resolve(pairing_ref).reveal()
    session_secret = broker.resolve(signing_ref).reveal().encode("utf-8")
    if len(session_secret) < MINIMUM_SESSION_SECRET_BYTES:
        raise ValueError("session_secret_too_short")
    instance_token = broker.resolve(instance_ref).reveal() if instance_ref is not None else None
    return create_app(
        database=database.expanduser().resolve(),
        bootstrap_token=bootstrap_token,
        session_secret=session_secret,
        static_web_dir=static_web_dir,
        allowed_origins=allowed_origins,
        allow_existing_user_pairing=allow_existing_user_pairing,
        instance_token=instance_token,
    )


def _emit(value: Any, *, json_output: bool) -> None:
    if hasattr(value, "model_dump"):
        value = value.model_dump(mode="json")
    if json_output:
        typer.echo(json.dumps(value, ensure_ascii=False, sort_keys=True))
        return
    if isinstance(value, dict):
        for key, item in value.items():
            typer.echo(f"{key}: {item}")
        return
    typer.echo(str(value))


def _fail(error: Exception) -> None:
    if isinstance(error, (DomainConflict, DomainNotFound, ValidationError, ValueError)):
        raise typer.BadParameter(str(error)) from error
    raise error


@project_app.command("create")
def project_create(
    name: str,
    database: DatabaseOption = Path("corvus-mvp.sqlite3"),
    json_output: JsonOption = False,
    tenant_id: Annotated[str, typer.Option("--tenant-id")] = "local",
) -> None:
    try:
        project = _service(database).create_project(name=name, tenant_id=tenant_id)
    except Exception as error:
        _fail(error)
        return
    _emit(project, json_output=json_output)


@outcome_app.command("create")
def outcome_create(
    project_id: str,
    title: str,
    criterion: Annotated[list[str] | None, typer.Option("--criterion")] = None,
    database: DatabaseOption = Path("corvus-mvp.sqlite3"),
    json_output: JsonOption = False,
) -> None:
    try:
        outcome = _service(database).create_outcome(
            project_id=project_id,
            title=title,
            acceptance_criteria=criterion or (),
        )
    except Exception as error:
        _fail(error)
        return
    _emit(outcome, json_output=json_output)


@workflow_app.command("create")
def workflow_create(
    outcome_id: str,
    name: str,
    items_json: Annotated[str, typer.Option("--items-json")],
    database: DatabaseOption = Path("corvus-mvp.sqlite3"),
    json_output: JsonOption = False,
) -> None:
    try:
        raw_items = json.loads(items_json)
        if not isinstance(raw_items, list):
            raise ValueError("items_json_must_be_an_array")
        definitions = tuple(WorkItemDefinition.model_validate(item) for item in raw_items)
        workflow = _service(database).create_workflow(
            outcome_id=outcome_id,
            name=name,
            items=definitions,
        )
    except Exception as error:
        _fail(error)
        return
    _emit(workflow, json_output=json_output)


@workflow_app.command("start")
def workflow_start(
    workflow_id: str,
    database: DatabaseOption = Path("corvus-mvp.sqlite3"),
    json_output: JsonOption = False,
) -> None:
    try:
        workflow = _service(database).start_workflow(workflow_id)
    except Exception as error:
        _fail(error)
        return
    _emit(workflow, json_output=json_output)


@workflow_app.command("status")
def workflow_status(
    workflow_id: str,
    database: DatabaseOption = Path("corvus-mvp.sqlite3"),
    json_output: JsonOption = False,
) -> None:
    try:
        workflow = _service(database).get_workflow(workflow_id)
    except Exception as error:
        _fail(error)
        return
    _emit(workflow, json_output=json_output)


@workflow_app.command("run-next")
def workflow_run_next(
 
[truncated — 13751 more characters]
```

### corvus/platform/api/app.py

```python
from __future__ import annotations

from fastapi import APIRouter

from corvus.platform.api.dependencies import IdentityApiDependencies
from corvus.platform.api.identity import create_identity_router
from corvus.platform.api.sync import create_sync_router


def create_platform_router(
    dependencies: IdentityApiDependencies | None,
) -> APIRouter:
    router = APIRouter()
    router.include_router(create_identity_router(dependencies))
    router.include_router(create_sync_router(dependencies))
    return router

```

[369 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]