Update expo application
This commit is contained in:
@@ -1,269 +1,420 @@
|
||||
# Spoon
|
||||
<p align="center">
|
||||
<img src="apps/next/public/favicon.png" alt="Spoon logo" width="96" height="96" />
|
||||
</p>
|
||||
|
||||
Spoon is a self-hostable fork maintenance cockpit.
|
||||
<h1 align="center">Spoon</h1>
|
||||
|
||||
Forking a project should not mean supporting it alone. Spoon tracks managed
|
||||
forks, called **Spoons**, watches upstream for drift, automatically syncs clean
|
||||
forks when it can, and opens durable **Threads** when upstream changes need
|
||||
review, context, or code.
|
||||
<p align="center">
|
||||
<strong>Fork freely & keep them all intimately close to upstream.</strong>
|
||||
</p>
|
||||
|
||||
This repository is the Spoon application itself, not a generic starter.
|
||||
<p align="center">
|
||||
Spoon is a self-hostable fork maintenance cockpit built around managed forks,
|
||||
durable maintenance threads, and OpenCode-powered workspaces.
|
||||
</p>
|
||||
|
||||
## What Spoon Does
|
||||
<p align="center">
|
||||
<a href="#what-this-is">What this is</a>
|
||||
·
|
||||
<a href="#product-model">Product model</a>
|
||||
·
|
||||
<a href="#architecture">Architecture</a>
|
||||
·
|
||||
<a href="#environment-reference">Environment</a>
|
||||
</p>
|
||||
|
||||
- Tracks GitHub-backed managed forks and their upstream projects.
|
||||
- Shows raw and effective drift, fork-only commits, pull requests, clone URLs,
|
||||
additional remotes, sync history, and open maintenance work.
|
||||
- Uses Threads as the product center for upstream reviews, merge conflicts,
|
||||
ignored commits, user-requested changes, worker logs, and draft PR handoff.
|
||||
- Auto-syncs clean behind forks when there are no fork-only commits.
|
||||
- Creates maintenance threads when custom fork work means upstream changes need
|
||||
a decision.
|
||||
- Runs optional OpenCode-backed workspaces in isolated agent-job containers.
|
||||
- Lets users configure encrypted AI provider profiles, Codex/OpenCode auth,
|
||||
per-Spoon secrets, commands, and agent settings.
|
||||
- Opens draft PRs for code changes instead of auto-merging custom forks.
|
||||
---
|
||||
|
||||
## Current Scope
|
||||
## What This Is
|
||||
|
||||
Implemented today:
|
||||
Spoon is a private, actively evolving project for making forks less lonely to
|
||||
maintain.
|
||||
|
||||
- Public Next.js landing page for Spoon's thread-first maintenance model.
|
||||
- Authenticated web routes:
|
||||
- `/dashboard`
|
||||
- `/spoons`
|
||||
- `/spoons/new`
|
||||
- `/spoons/[spoonId]`
|
||||
- `/spoons/[spoonId]/agent/[jobId]`
|
||||
- `/threads`
|
||||
- `/threads/[threadId]`
|
||||
- `/settings/profile`
|
||||
- `/settings/integrations`
|
||||
- `/settings/ai-providers`
|
||||
- Legacy `/updates` and `/agents` routes redirect into Threads.
|
||||
- GitHub App connection, repository listing, fork creation, drift refresh,
|
||||
commit/PR cache, and safe sync foundation.
|
||||
- Thread-first maintenance model with ignored upstream changes and effective
|
||||
drift.
|
||||
- Optional `apps/agent-worker` service that claims queued jobs, clones the
|
||||
current GitHub fork, starts an isolated workspace, exposes file browsing and
|
||||
edits through server-side Next proxies, runs commands, and opens draft PRs.
|
||||
- Browser workspace with persisted thread messages, file tree, Monaco editor
|
||||
with optional Vim mode, diff view, command panel, logs, artifacts, and draft
|
||||
PR actions.
|
||||
- Encrypted per-user AI provider profiles and per-Spoon project secrets.
|
||||
- Password auth and Authentik/GitHub OAuth through Convex Auth.
|
||||
- Expo companion app shell with password and Authentik sign-in.
|
||||
- Self-hosted local Convex using Postgres storage.
|
||||
Forking a project is easy. Keeping that fork close to upstream after you add
|
||||
custom changes is the hard part. Spoon treats a fork as an ongoing relationship:
|
||||
it watches upstream, understands fork-only commits, automatically syncs clean
|
||||
drift when it can, and opens a durable **Thread** when a decision needs context
|
||||
or code.
|
||||
|
||||
Not implemented yet:
|
||||
The application is currently GitHub-first. Future provider-neutral fields exist
|
||||
in the data model, but GitHub is the active automation surface today.
|
||||
|
||||
- Automatic merge of custom/diverged forks.
|
||||
- Git provider automation beyond GitHub.
|
||||
- Additional remotes as push targets.
|
||||
- Long-running service-stack orchestration inside agent jobs.
|
||||
- Direct browser access to worker containers.
|
||||
- Production mobile build/release setup.
|
||||
## Highlights
|
||||
|
||||
- **Managed forks, called Spoons**
|
||||
Track upstream metadata, fork metadata, clone URLs, extra remotes, sync
|
||||
cadence, production-ref strategy, fork-only commits, and pull requests.
|
||||
|
||||
- **Thread-first maintenance**
|
||||
Upstream updates, conflict review, ignore decisions, user-requested work,
|
||||
worker output, and draft PR handoff all live inside Threads.
|
||||
|
||||
- **Clean drift auto-sync**
|
||||
If upstream moves and the fork has no custom commits, Spoon can fast-forward
|
||||
the fork without creating busywork.
|
||||
|
||||
- **Custom forks get context**
|
||||
If the fork has custom commits, Spoon creates a maintenance thread rather than
|
||||
pretending the update is trivial.
|
||||
|
||||
- **Effective drift**
|
||||
Spoon keeps raw GitHub drift visible while also tracking ignored upstream
|
||||
changes so irrelevant commits do not keep a fork permanently actionable.
|
||||
|
||||
- **OpenCode workspaces**
|
||||
Agent work happens in an isolated workspace with a file tree, browser editor,
|
||||
diff viewer, command panel, logs, artifacts, and draft PR actions.
|
||||
|
||||
- **User-owned providers and secrets**
|
||||
AI provider profiles, Codex/OpenCode auth, and per-Spoon project secrets are
|
||||
encrypted. Secrets are redacted from logs and refused from commits when
|
||||
materialized into env files.
|
||||
|
||||
- **Draft PR handoff**
|
||||
Code changes become branches and draft pull requests. Spoon does not
|
||||
auto-merge custom forks behind the user's back.
|
||||
|
||||
## Product Model
|
||||
|
||||
<details open>
|
||||
<summary><strong>Spoons</strong></summary>
|
||||
|
||||
A **Spoon** is a managed fork. It records the upstream project, the fork
|
||||
repository, default branches, sync policy, extra remotes, current drift, cached
|
||||
commits, cached pull requests, secrets, and agent settings.
|
||||
|
||||
Spoons are the durable project-level objects. They answer:
|
||||
|
||||
- What did I fork?
|
||||
- Where does my fork live?
|
||||
- How far has it drifted?
|
||||
- Which commits are mine?
|
||||
- Which upstream changes matter?
|
||||
- What threads or PRs are open?
|
||||
|
||||
</details>
|
||||
|
||||
<details open>
|
||||
<summary><strong>Threads</strong></summary>
|
||||
|
||||
A **Thread** is the durable place where Spoon talks about maintenance work.
|
||||
Threads can be created by a user or by the system.
|
||||
|
||||
Common thread sources:
|
||||
|
||||
- `user_request`: user asks Spoon to change a fork.
|
||||
- `upstream_update`: upstream moved and the fork needs review.
|
||||
- `merge_conflict`: a sync conflict needs context or code.
|
||||
- `manual_review`: user explicitly asks for a review.
|
||||
- `system`: internal maintenance coordination.
|
||||
|
||||
Threads hold messages, status, outcomes, related sync runs, related jobs,
|
||||
workspace links, draft PR links, and ignored upstream decisions.
|
||||
|
||||
</details>
|
||||
|
||||
<details open>
|
||||
<summary><strong>Maintenance decisions</strong></summary>
|
||||
|
||||
Spoon's maintenance policy is intentionally conservative:
|
||||
|
||||
| Situation | Default action |
|
||||
| ------------------------------------------ | ------------------------------------- |
|
||||
| No fork-only commits and upstream is ahead | Auto-sync |
|
||||
| Fork-only commits and upstream is ahead | Create a maintenance thread |
|
||||
| Merge conflicts | Open or continue a workspace thread |
|
||||
| Irrelevant upstream changes | Record an intentional ignore decision |
|
||||
| Agent/code changes | Open a draft PR |
|
||||
|
||||
The goal is to keep forks close without hiding risk or skipping review when
|
||||
custom work exists.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>OpenCode workspaces</strong></summary>
|
||||
|
||||
Spoon's optional agent worker is designed to run outside Convex actions. The
|
||||
worker claims queued jobs, clones the current GitHub fork, creates a branch,
|
||||
starts an isolated workspace, and exposes workspace operations to the Next app
|
||||
through server-only API proxies.
|
||||
|
||||
Workspace capabilities:
|
||||
|
||||
- browse repository files
|
||||
- edit files in a browser editor
|
||||
- use optional Vim keybindings
|
||||
- inspect diffs
|
||||
- send thread messages to the agent
|
||||
- run configured commands
|
||||
- store logs and artifacts
|
||||
- push a branch
|
||||
- open a draft PR
|
||||
|
||||
The browser never receives worker tokens and never talks directly to the worker
|
||||
or job container.
|
||||
|
||||
</details>
|
||||
|
||||
## Architecture
|
||||
|
||||
- `apps/next`: Next.js 16 web app and primary product UI.
|
||||
- `apps/agent-worker`: optional server-side worker for OpenCode workspaces and
|
||||
draft PR jobs.
|
||||
- `apps/expo`: Expo companion app.
|
||||
- `packages/backend/convex`: self-hosted Convex schema, functions, auth, and
|
||||
HTTP routes.
|
||||
- `packages/ui`: shared shadcn-based UI components.
|
||||
- `tools`: shared ESLint, Prettier, Tailwind, TypeScript, and Vitest config.
|
||||
- `docker`: local and production Compose files.
|
||||
- `scripts`: environment, database, codegen, and CI helpers.
|
||||
|
||||
Core domain objects:
|
||||
|
||||
- `spoons`: managed fork records.
|
||||
- `threads`: durable maintenance and work conversations.
|
||||
- `threadMessages`: persisted thread messages.
|
||||
- `syncRuns`: upstream checks, sync attempts, and maintenance decisions.
|
||||
- `ignoredUpstreamChanges`: intentional ignore decisions that affect effective
|
||||
drift.
|
||||
- `gitConnections`: Git provider connection metadata.
|
||||
- `agentJobs`: worker-executed workspace jobs and PR lifecycle.
|
||||
- `agentJobEvents` and `agentJobArtifacts`: logs and structured job outputs.
|
||||
- `agentWorkspaceChanges`: recorded file changes from user, agent, or command
|
||||
activity.
|
||||
- `spoonSecrets`: encrypted per-Spoon environment variables.
|
||||
- `spoonAgentSettings`: per-Spoon runtime, branch, command, and env-file
|
||||
settings.
|
||||
- `aiProviderProfiles`: encrypted provider/auth profiles used by OpenCode.
|
||||
|
||||
## Local Setup
|
||||
|
||||
Requirements:
|
||||
|
||||
- Bun 1.3.10
|
||||
- Node 22
|
||||
- Docker or Podman
|
||||
- Infisical CLI
|
||||
|
||||
```sh
|
||||
bun install --frozen-lockfile
|
||||
infisical login
|
||||
infisical init
|
||||
bun db:up
|
||||
bun dev:next
|
||||
```
|
||||
|
||||
Local services:
|
||||
|
||||
- Next.js: `http://localhost:3000`
|
||||
- Convex API: `http://localhost:3210`
|
||||
- Convex site HTTP routes: `http://localhost:3211`
|
||||
- Convex dashboard: `http://localhost:6791`
|
||||
- Convex Postgres: `localhost:5432`
|
||||
|
||||
Next and Expo run on the host. Local Convex runs in containers with Postgres
|
||||
storage. Normal `bun db:up` never contacts staging; it starts local Postgres,
|
||||
Convex, and the dashboard, generates a machine-local Convex admin key in
|
||||
`.local/dev.generated.env` when needed, deploys functions/schema, and configures
|
||||
local Convex Auth keys.
|
||||
|
||||
```sh
|
||||
bun db:down # stop; preserve local data
|
||||
bun db:down:wipe # remove local data volumes and generated admin key
|
||||
```
|
||||
|
||||
Use staging services explicitly:
|
||||
|
||||
```sh
|
||||
INFISICAL_ENV=staging bun dev:next
|
||||
```
|
||||
|
||||
Run the optional local agent worker in a separate terminal:
|
||||
|
||||
```sh
|
||||
bun dev:agent
|
||||
```
|
||||
|
||||
The worker starts an internal HTTP API, defaulting to `http://localhost:3921`,
|
||||
for server-side Next route handlers. The browser never receives the worker token
|
||||
or talks to this API directly.
|
||||
|
||||
The Docker Compose local worker service is disabled by default behind the
|
||||
`agent` profile. Build the job image before using Docker-backed jobs:
|
||||
|
||||
```sh
|
||||
docker build -f docker/agent-job.Dockerfile -t spoon-agent-job:latest .
|
||||
docker compose -f docker/compose.local.yml --profile agent up spoon-agent-worker
|
||||
```
|
||||
|
||||
The job image includes the OpenCode CLI. Rebuild it after changes to
|
||||
`docker/agent-job.Dockerfile`.
|
||||
|
||||
## Environment Model
|
||||
|
||||
Local `dev` and `staging` values come from Infisical through
|
||||
`scripts/with-env`. App commands do not fall back to root `.env` files.
|
||||
|
||||
Generated local state belongs in:
|
||||
<details open>
|
||||
<summary><strong>Workspace layout</strong></summary>
|
||||
|
||||
```txt
|
||||
.local/<environment>.generated.env
|
||||
.
|
||||
├── apps
|
||||
│ ├── next # Next.js 16 web app and primary Spoon UI
|
||||
│ ├── agent-worker # Optional OpenCode workspace / draft PR worker
|
||||
│ └── expo # Expo companion app scaffold
|
||||
├── packages
|
||||
│ ├── backend # Convex backend package
|
||||
│ │ └── convex # Schema, functions, auth, HTTP routes
|
||||
│ └── ui # Shared shadcn-based UI components
|
||||
├── tools # Shared lint, format, Tailwind, TS, Vitest config
|
||||
├── docker # Compose files and worker/job Dockerfiles
|
||||
└── scripts # Env, Convex, codegen, database, and CI helpers
|
||||
```
|
||||
|
||||
CI uses Gitea-provided secrets or `CI_ENV_FILE` and must not call Infisical.
|
||||
</details>
|
||||
|
||||
Useful helpers:
|
||||
<details>
|
||||
<summary><strong>Core tables</strong></summary>
|
||||
|
||||
| Table | Purpose |
|
||||
| ------------------------ | --------------------------------------------------------- |
|
||||
| `spoons` | Managed fork records |
|
||||
| `threads` | Durable maintenance and work conversations |
|
||||
| `threadMessages` | Messages inside threads |
|
||||
| `syncRuns` | Upstream checks, sync attempts, and maintenance decisions |
|
||||
| `ignoredUpstreamChanges` | Intentional ignore records that affect effective drift |
|
||||
| `gitConnections` | Git provider connection metadata |
|
||||
| `spoonRepositoryStates` | Latest cached upstream/fork state |
|
||||
| `spoonCommits` | Cached upstream and fork-only commits |
|
||||
| `spoonPullRequests` | Cached fork/upstream pull requests |
|
||||
| `spoonSecrets` | Encrypted per-Spoon environment variables |
|
||||
| `spoonAgentSettings` | Per-Spoon runtime, branch, command, and env-file settings |
|
||||
| `aiProviderProfiles` | Encrypted provider/auth profiles used by OpenCode |
|
||||
| `agentJobs` | Worker-executed workspace jobs and PR lifecycle |
|
||||
| `agentJobEvents` | Append-only worker event log |
|
||||
| `agentJobArtifacts` | Diffs, summaries, command output, PR body drafts |
|
||||
| `agentWorkspaceChanges` | Recorded user, agent, and command file changes |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Important routes</strong></summary>
|
||||
|
||||
| Route | Purpose |
|
||||
| --------------------------------- | --------------------------------------- |
|
||||
| `/` | Public product landing page |
|
||||
| `/dashboard` | Maintenance overview |
|
||||
| `/spoons` | Managed fork list |
|
||||
| `/spoons/new` | Manual/GitHub Spoon creation |
|
||||
| `/spoons/[spoonId]` | Spoon detail dashboard |
|
||||
| `/spoons/[spoonId]/agent/[jobId]` | Interactive workspace |
|
||||
| `/threads` | Global thread queue |
|
||||
| `/threads/[threadId]` | Thread detail |
|
||||
| `/settings/profile` | User profile settings |
|
||||
| `/settings/integrations` | GitHub and service integration settings |
|
||||
| `/settings/ai-providers` | AI/OpenCode provider profiles |
|
||||
|
||||
Legacy `/updates` and `/agents` routes redirect into `/threads`.
|
||||
|
||||
</details>
|
||||
|
||||
## Mobile App
|
||||
|
||||
<details open>
|
||||
<summary><strong>Current Expo scope</strong></summary>
|
||||
|
||||
`apps/expo` is the mobile Spoon client. It is designed to mirror the core web
|
||||
product without exposing worker internals or trying to turn a phone into the
|
||||
primary code-editing surface.
|
||||
|
||||
The mobile app currently supports:
|
||||
|
||||
- password, GitHub, and Authentik sign-in
|
||||
- Dashboard, Spoons, Threads, Workspace Review, and Settings tabs/screens
|
||||
- manual Spoon creation and GitHub-assisted repository tracking
|
||||
- Spoon detail views for overview, upstream commits, fork-only commits, PRs,
|
||||
threads, settings, clone URLs, and additional remotes
|
||||
- Spoon maintenance settings, agent settings, encrypted secrets, and bulk
|
||||
`.env` paste import
|
||||
- thread list/detail, message composer, resolve/cancel actions, and workspace
|
||||
review links
|
||||
- GitHub integration status and repository listing
|
||||
- AI provider profile management, including Codex/OpenCode auth JSON
|
||||
- read-only workspace review for job status, messages, diffs, events,
|
||||
artifacts, and draft PR links
|
||||
|
||||
The mobile app intentionally does not currently support:
|
||||
|
||||
- live workspace file browsing/editing
|
||||
- mobile command execution
|
||||
- direct mobile calls to the agent worker HTTP API
|
||||
- mobile access to worker/container tokens
|
||||
- long-running app preview stacks
|
||||
- production app-store/EAS release flow
|
||||
|
||||
Mobile workspace editing is deferred until worker authorization and mobile
|
||||
editor UX are designed explicitly. For now, the phone is a strong review and
|
||||
control surface; the browser remains the code workspace.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Expo validation</strong></summary>
|
||||
|
||||
Useful mobile checks:
|
||||
|
||||
```sh
|
||||
sh scripts/with-env dev -- <command>
|
||||
sh scripts/export-env dev
|
||||
bun sync:convex
|
||||
bun sync:convex:staging
|
||||
bun --filter @spoon/expo lint
|
||||
bun --filter @spoon/expo typecheck
|
||||
bun --filter @spoon/expo test:unit
|
||||
bun --filter @spoon/expo test:component
|
||||
```
|
||||
|
||||
### Convex Deployment Env
|
||||
The Expo unit tests cover pure utilities such as `.env` parsing and formatting.
|
||||
The component tests use a lightweight React Native mock layer to exercise shared
|
||||
mobile controls, higher-value forms, and route smoke renders without booting a
|
||||
native simulator.
|
||||
|
||||
Convex functions and HTTP actions read environment variables from the Convex
|
||||
deployment environment, not directly from the host process. OAuth providers,
|
||||
GitHub App credentials, UseSend, encryption keys, worker tokens, and Convex Auth
|
||||
signing keys must be synced into the selected Convex deployment.
|
||||
</details>
|
||||
|
||||
`packages/backend` runs `scripts/sync-convex-env` before `convex dev`, so
|
||||
`bun dev:next`, `bun dev:backend`, and `bun db:up` sync the relevant Infisical
|
||||
values into local Convex first. Run it manually when needed:
|
||||
## Environment Reference
|
||||
|
||||
```sh
|
||||
sh scripts/sync-convex-env dev
|
||||
sh scripts/sync-convex-env staging
|
||||
INFISICAL_ENV=staging bun sync:convex
|
||||
```
|
||||
This project is currently private, so this section is a reference for what the
|
||||
application expects rather than public setup documentation.
|
||||
|
||||
For local `dev`, `JWT_PRIVATE_KEY`, `JWKS`, `SPOON_ENCRYPTION_KEY`,
|
||||
`SPOON_WORKER_TOKEN`, and related generated values are created automatically if
|
||||
they are not already present. The generated Convex admin key remains
|
||||
machine-local in `.local/dev.generated.env`; do not put it in Infisical.
|
||||
<details open>
|
||||
<summary><strong>Public Next variables</strong></summary>
|
||||
|
||||
Local OAuth callback URLs:
|
||||
| Variable | Used for |
|
||||
| --------------------------------- | ------------------------------------------- |
|
||||
| `NEXT_PUBLIC_SITE_URL` | Canonical Spoon web URL |
|
||||
| `NEXT_PUBLIC_CONVEX_URL` | Convex client URL |
|
||||
| `NEXT_PUBLIC_DEPLOYMENT_URL` | Convex dashboard/deployment URL when needed |
|
||||
| `NEXT_PUBLIC_PLAUSIBLE_URL` | Plausible analytics endpoint |
|
||||
| `NEXT_PUBLIC_SENTRY_DSN` | Browser Sentry DSN |
|
||||
| `NEXT_PUBLIC_SENTRY_URL` | Sentry instance URL |
|
||||
| `NEXT_PUBLIC_SENTRY_ORG` | Sentry organization |
|
||||
| `NEXT_PUBLIC_SENTRY_PROJECT_NAME` | Sentry project name |
|
||||
|
||||
```txt
|
||||
http://localhost:3211/api/auth/callback/authentik
|
||||
http://localhost:3211/api/auth/callback/github
|
||||
```
|
||||
</details>
|
||||
|
||||
If GitHub App actions fail with `GITHUB_APP_PRIVATE_KEY is not configured`, add
|
||||
the full PEM contents to Infisical as `GITHUB_APP_PRIVATE_KEY` and rerun the
|
||||
sync command.
|
||||
<details>
|
||||
<summary><strong>Auth and email</strong></summary>
|
||||
|
||||
## Development
|
||||
| Variable | Used for |
|
||||
| ----------------------- | ----------------------------- |
|
||||
| `SITE_URL` | Convex Auth site URL |
|
||||
| `JWT_PRIVATE_KEY` | Convex Auth signing key |
|
||||
| `JWKS` | Convex Auth JWKS |
|
||||
| `AUTH_AUTHENTIK_ID` | Authentik OAuth client ID |
|
||||
| `AUTH_AUTHENTIK_SECRET` | Authentik OAuth client secret |
|
||||
| `AUTH_AUTHENTIK_ISSUER` | Authentik issuer URL |
|
||||
| `AUTH_GITHUB_ID` | GitHub OAuth client ID |
|
||||
| `AUTH_GITHUB_SECRET` | GitHub OAuth client secret |
|
||||
| `USESEND_API_KEY` | UseSend API key |
|
||||
| `USESEND_URL` | UseSend API URL |
|
||||
| `USESEND_FROM_EMAIL` | Transactional email sender |
|
||||
|
||||
```sh
|
||||
bun dev:next
|
||||
bun dev:expo
|
||||
bun dev:agent
|
||||
```
|
||||
</details>
|
||||
|
||||
Physical devices cannot resolve their own `localhost`; override the public
|
||||
Convex URL with the development host's LAN address when testing Expo on-device.
|
||||
<details>
|
||||
<summary><strong>GitHub App</strong></summary>
|
||||
|
||||
Shared dependency versions belong in root catalogs. Edit the root catalog, run
|
||||
`bun install`, then `bun lint:ws`. Do not run `bun update` inside a workspace.
|
||||
| Variable | Used for |
|
||||
| ---------------------------- | ---------------------------------- |
|
||||
| `GITHUB_APP_ID` | GitHub App ID |
|
||||
| `GITHUB_APP_CLIENT_ID` | GitHub App OAuth client ID |
|
||||
| `GITHUB_APP_CLIENT_SECRET` | GitHub App OAuth client secret |
|
||||
| `GITHUB_APP_PRIVATE_KEY` | GitHub App PEM private key |
|
||||
| `GITHUB_APP_WEBHOOK_SECRET` | GitHub webhook verification secret |
|
||||
| `GITHUB_APP_SLUG` | GitHub App slug |
|
||||
| `GITHUB_APP_INSTALLATION_ID` | Default/local installation ID |
|
||||
| `GITHUB_APP_OWNER` | Default/local installation owner |
|
||||
|
||||
## Validation
|
||||
</details>
|
||||
|
||||
Routine checks:
|
||||
<details>
|
||||
<summary><strong>Convex, storage, and runtime</strong></summary>
|
||||
|
||||
```sh
|
||||
bun lint:ws
|
||||
bun format
|
||||
bun lint
|
||||
bun typecheck
|
||||
bun run test
|
||||
```
|
||||
| Variable | Used for |
|
||||
| ----------------------------------- | ----------------------------------------------- |
|
||||
| `CONVEX_SELF_HOSTED_URL` | Self-hosted Convex API URL |
|
||||
| `CONVEX_SELF_HOSTED_ADMIN_KEY` | Admin key for deploying/syncing Convex |
|
||||
| `CONVEX_CLOUD_ORIGIN` | Convex backend origin |
|
||||
| `CONVEX_SITE_ORIGIN` | Convex site-function origin |
|
||||
| `CONVEX_SITE_URL` | Site URL seen by Convex Auth |
|
||||
| `POSTGRES_URL` | Convex storage database URL |
|
||||
| `SPOON_ENCRYPTION_KEY` | Encryption key for stored secrets/provider auth |
|
||||
| `SPOON_WORKER_TOKEN` | Worker token for Convex worker mutations |
|
||||
| `SPOON_AGENT_WORKER_URL` | Internal worker HTTP URL used by Next |
|
||||
| `SPOON_AGENT_WORKER_HTTP_PORT` | Worker HTTP port |
|
||||
| `SPOON_AGENT_WORKER_INTERNAL_TOKEN` | Server-only token for Next-to-worker proxy |
|
||||
| `SPOON_AGENT_JOB_IMAGE` | Agent job container image |
|
||||
| `SPOON_AGENT_RUNTIME` | Runtime mode, currently Docker/Podman-oriented |
|
||||
| `SPOON_AGENT_MAX_CONCURRENT_JOBS` | Worker concurrency limit |
|
||||
| `SPOON_AGENT_JOB_TIMEOUT_MS` | Job timeout |
|
||||
| `SPOON_AGENT_WORKDIR` | Worker work directory |
|
||||
| `SPOON_AGENT_NETWORK` | Optional job container network |
|
||||
|
||||
Full local gate without e2e:
|
||||
</details>
|
||||
|
||||
```sh
|
||||
SKIP_E2E=1 bun run ci:check
|
||||
```
|
||||
<details>
|
||||
<summary><strong>Deployment and observability</strong></summary>
|
||||
|
||||
Local-stack smoke e2e:
|
||||
| Variable | Used for |
|
||||
| ----------------------- | --------------------------------- |
|
||||
| `NODE_ENV` | Runtime environment |
|
||||
| `SENTRY_AUTH_TOKEN` | Sentry source map/upload auth |
|
||||
| `REDACT_LOGS_TO_CLIENT` | Convex log redaction setting |
|
||||
| `DISABLE_BEACON` | Self-hosted Convex beacon setting |
|
||||
| `DO_NOT_REQUIRE_SSL` | Self-hosted Convex SSL behavior |
|
||||
| `CI_ENV_FILE` | CI-provided env file path |
|
||||
|
||||
```sh
|
||||
bun test:e2e
|
||||
```
|
||||
</details>
|
||||
|
||||
`bun test:e2e` starts the isolated local stack when needed and stops it
|
||||
afterward only when it was not already running.
|
||||
## Current Status
|
||||
|
||||
Use `bun run test`, not bare `bun test`; bare `bun test` invokes Bun's built-in
|
||||
test runner instead of the repo's Turbo/Vitest test script.
|
||||
<details open>
|
||||
<summary><strong>Implemented</strong></summary>
|
||||
|
||||
## Deployment
|
||||
- Thread-first Next.js product shell
|
||||
- GitHub App connection and fork creation foundation
|
||||
- GitHub drift refresh, commit cache, PR cache, and sync-run history
|
||||
- Effective drift and ignored upstream change records
|
||||
- Global Threads page and Spoon-scoped Threads tab
|
||||
- OpenCode-oriented agent worker and browser workspace foundation
|
||||
- Monaco editor with optional Vim mode
|
||||
- Diff viewer, command panel, worker logs, and artifacts
|
||||
- Encrypted Spoon secrets and bulk `.env` import
|
||||
- Encrypted AI provider profiles, including Codex/OpenCode auth support
|
||||
- Authentik, GitHub, and password auth through Convex Auth
|
||||
- Self-hosted Convex/Postgres deployment model
|
||||
|
||||
Production Compose runs the Next image, self-hosted Convex backend/dashboard,
|
||||
and Postgres. The deployed Next image is expected to be named
|
||||
`spoon-next:latest` in the Gitea registry.
|
||||
</details>
|
||||
|
||||
Gitea runs the quality gate first, runs Convex codegen with deployment env,
|
||||
builds the Next image from injected secrets or `CI_ENV_FILE`, then pushes SHA
|
||||
and `latest` tags. CI never installs or invokes Infisical.
|
||||
<details>
|
||||
<summary><strong>Intentionally not done yet</strong></summary>
|
||||
|
||||
- Autonomous merging for custom/diverged forks
|
||||
- Non-GitHub provider automation
|
||||
- Pushing agent branches to additional remotes
|
||||
- Long-running preview stacks for arbitrary forked projects
|
||||
- Direct browser access to worker containers
|
||||
- Public self-hosting setup documentation
|
||||
- Production mobile release flow
|
||||
|
||||
</details>
|
||||
|
||||
## Notes
|
||||
|
||||
Spoon is built for a very specific maintenance problem: "I want to fork this
|
||||
project, but I do not want to permanently become its maintenance team."
|
||||
|
||||
The current product direction is to make that maintenance visible, threaded,
|
||||
reviewable, and increasingly automated where it is safe. Clean forks can stay
|
||||
close automatically. Custom forks get context, workspace help, and draft PRs.
|
||||
|
||||
Reference in New Issue
Block a user