Update README.md & fix test
This commit is contained in:
@@ -1,76 +1,102 @@
|
||||
# Spoon
|
||||
|
||||
Spoon is a self-hostable fork maintenance dashboard.
|
||||
Spoon is a self-hostable fork maintenance cockpit.
|
||||
|
||||
The product goal is simple: make it practical to fork a project, customize it,
|
||||
and still stay close to upstream. Spoon tracks managed forks, called
|
||||
**Spoons**, and lays the foundation for upstream update checks, AI-assisted
|
||||
change review, and agent-authored merge requests.
|
||||
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.
|
||||
|
||||
This repository is the Spoon application itself, not a generic starter.
|
||||
|
||||
## Current scope
|
||||
## What Spoon Does
|
||||
|
||||
- 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
|
||||
|
||||
Implemented today:
|
||||
|
||||
- Public Spoon landing page in Next.js.
|
||||
- Authenticated web dashboard routes:
|
||||
- Public Next.js landing page for Spoon's thread-first maintenance model.
|
||||
- Authenticated web routes:
|
||||
- `/dashboard`
|
||||
- `/spoons`
|
||||
- `/spoons/new`
|
||||
- `/updates`
|
||||
- `/spoons/[spoonId]`
|
||||
- `/settings`
|
||||
- Manual and GitHub-created Spoon records stored in Convex.
|
||||
- `/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 manual sync foundation.
|
||||
- Per-user OpenAI settings for upstream compatibility review.
|
||||
- Per-Spoon encrypted project secrets and agent runtime settings.
|
||||
- Optional `apps/agent-worker` service that can claim queued jobs, clone the
|
||||
GitHub fork, keep an interactive workspace active, expose file browsing and
|
||||
edits through a server-side proxy, run selected commands, call OpenCode or the
|
||||
OpenAI direct fallback, push a branch, and open a draft PR.
|
||||
- Browser agent workspace at `/spoons/[spoonId]/agent/[jobId]` with persisted
|
||||
thread messages, file tree, Monaco editor with optional Vim mode, diff view,
|
||||
command panel, and draft PR actions.
|
||||
- Password auth and Authentik OAuth through Convex Auth.
|
||||
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.
|
||||
|
||||
Not implemented yet:
|
||||
|
||||
- Automatic merge.
|
||||
- Additional Git provider automation beyond preserving provider-neutral fields.
|
||||
- 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 agent containers.
|
||||
- Direct browser access to worker containers.
|
||||
- Production mobile build/release setup.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `apps/next`: Next.js 16 web app and primary product UI.
|
||||
- `apps/agent-worker`: optional server-side worker for queued coding-agent jobs.
|
||||
- `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, and CI helpers.
|
||||
- `scripts`: environment, database, codegen, and CI helpers.
|
||||
|
||||
The core domain objects are:
|
||||
Core domain objects:
|
||||
|
||||
- `spoons`: managed fork records.
|
||||
- `gitConnections`: future Git provider connection metadata.
|
||||
- `syncRuns`: future upstream checks, merge attempts, and AI reviews.
|
||||
- `agentRequests`: prompt-driven agent work requests.
|
||||
- `agentJobs`: worker-executed coding-agent jobs and their PR lifecycle.
|
||||
- `agentJobMessages`: persisted per-job agent workspace thread messages.
|
||||
- `agentWorkspaceChanges`: recorded user, agent, and command workspace changes.
|
||||
- `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 agent model, branch, and command settings.
|
||||
- `spoonAgentSettings`: per-Spoon runtime, branch, command, and env-file
|
||||
settings.
|
||||
- `aiProviderProfiles`: encrypted provider/auth profiles used by OpenCode.
|
||||
|
||||
## Local setup
|
||||
## Local Setup
|
||||
|
||||
Requirements:
|
||||
|
||||
@@ -98,8 +124,8 @@ Local services:
|
||||
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.
|
||||
`.local/dev.generated.env` when needed, deploys functions/schema, and configures
|
||||
local Convex Auth keys.
|
||||
|
||||
```sh
|
||||
bun db:down # stop; preserve local data
|
||||
@@ -118,9 +144,9 @@ Run the optional local agent worker in a separate terminal:
|
||||
bun dev:agent
|
||||
```
|
||||
|
||||
The worker also 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 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:
|
||||
@@ -133,10 +159,10 @@ 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
|
||||
## Environment Model
|
||||
|
||||
Local `dev` and `staging` values come from Infisical through `scripts/with-env`.
|
||||
App commands do not fall back to root `.env` files.
|
||||
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:
|
||||
|
||||
@@ -152,17 +178,19 @@ Useful helpers:
|
||||
sh scripts/with-env dev -- <command>
|
||||
sh scripts/export-env dev
|
||||
bun sync:convex
|
||||
bun sync:convex:staging
|
||||
```
|
||||
|
||||
### Convex deployment env
|
||||
### Convex Deployment Env
|
||||
|
||||
Convex functions and HTTP actions read environment variables from the Convex
|
||||
deployment environment, not directly from the host process. For OAuth providers,
|
||||
that means Infisical values must also be present in local Convex env.
|
||||
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.
|
||||
|
||||
`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 the selected Convex deployment first. Run it manually when needed:
|
||||
values into local Convex first. Run it manually when needed:
|
||||
|
||||
```sh
|
||||
sh scripts/sync-convex-env dev
|
||||
@@ -170,41 +198,12 @@ sh scripts/sync-convex-env staging
|
||||
INFISICAL_ENV=staging bun sync:convex
|
||||
```
|
||||
|
||||
The sync includes:
|
||||
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.
|
||||
|
||||
```txt
|
||||
AUTH_AUTHENTIK_ID
|
||||
AUTH_AUTHENTIK_SECRET
|
||||
AUTH_AUTHENTIK_ISSUER
|
||||
AUTH_GITHUB_ID
|
||||
AUTH_GITHUB_SECRET
|
||||
GITHUB_APP_ID
|
||||
GITHUB_APP_CLIENT_ID
|
||||
GITHUB_APP_CLIENT_SECRET
|
||||
GITHUB_APP_PRIVATE_KEY
|
||||
GITHUB_APP_WEBHOOK_SECRET
|
||||
GITHUB_APP_SLUG
|
||||
GITHUB_APP_INSTALLATION_ID
|
||||
GITHUB_APP_OWNER
|
||||
SPOON_ENCRYPTION_KEY
|
||||
SPOON_WORKER_TOKEN
|
||||
SPOON_AGENT_WORKER_INTERNAL_TOKEN
|
||||
SPOON_AGENT_WORKER_HTTP_PORT
|
||||
SPOON_AGENT_WORKER_URL
|
||||
USESEND_API_KEY
|
||||
USESEND_URL
|
||||
USESEND_FROM_EMAIL
|
||||
JWT_PRIVATE_KEY
|
||||
JWKS
|
||||
SITE_URL
|
||||
```
|
||||
|
||||
For local `dev`, `JWT_PRIVATE_KEY`, `JWKS`, `SPOON_ENCRYPTION_KEY`, and
|
||||
`SPOON_WORKER_TOKEN` are generated automatically if they are not already present
|
||||
in Convex. The generated Convex admin key remains machine-local in
|
||||
`.local/dev.generated.env`; do not put it in Infisical.
|
||||
|
||||
The local OAuth callback URLs are:
|
||||
Local OAuth callback URLs:
|
||||
|
||||
```txt
|
||||
http://localhost:3211/api/auth/callback/authentik
|
||||
@@ -220,6 +219,7 @@ sync command.
|
||||
```sh
|
||||
bun dev:next
|
||||
bun dev:expo
|
||||
bun dev:agent
|
||||
```
|
||||
|
||||
Physical devices cannot resolve their own `localhost`; override the public
|
||||
@@ -260,9 +260,10 @@ test runner instead of the repo's Turbo/Vitest test script.
|
||||
|
||||
## Deployment
|
||||
|
||||
Production Compose keeps the self-hosted Convex backend/dashboard and expects
|
||||
`POSTGRES_URL` to be a database-cluster URL without a database path.
|
||||
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.
|
||||
|
||||
Gitea runs the quality gate first, builds the Next image from a temporary
|
||||
Gitea-secret env file, then pushes SHA and `latest` tags. CI never installs or
|
||||
invokes Infisical.
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user