Hosted repositories that grow themselves.
Connect a repo. A FlyBot agent writes a failing test, makes the smallest fix, and opens one PR you can review.
Fledge is a small, self-hosted platform for reviewable repository growth. A user signs in with GitHub, connects one or more repositories with a fine-grained token, and gives each repository a goal. Fledge hands the work to a FlyBot agent through a signed bridge; the agent writes a failing test, makes the smallest correct fix, opens one pull request, and reports back. Fledge never pushes to the default branch, does not merge by default, and never runs a user repository itself.
Status:
v0.3.1is the latest release (2026-11-11) at https://fledge.hugoxk.online/. A weekly minor release goes out on Monday night; later releases in the same week are patch releases. The GitHub token login fallback is active until the production OAuth App is configured. Documentation is at https://fledge-docs.hugoxk.online/docs/; the project homepage and guide are at https://hugoxk.online/fledge/.
- Why Fledge
- Features
- How it works
- Architecture
- Documentation
- Releases and docs
- Quick start
- Configuration
- Quota
- Security
- Deployment
- API
- Development
- Workflow
- Project layout
- Roadmap
- FAQ
- Contributing
- License
- Acknowledgements
Most “AI coding” tools optimize for a demo: a prompt, a diff, a video. Fledge optimizes for the artifact a maintainer actually needs: one focused pull request, with a test, at a tip anyone can re-run.
The name comes from a fledgling: a young bird that has grown its flight feathers and leaves the nest because it is ready, not because it was pushed. A repository in Fledge stays in your account, under your review, and gradually produces its own improvements. See docs/decisions/0001-name.md.
- A multi-repository control plane for a FlyBot agent.
- A per-user quota gateway (1 CNY by default) with an own-model fallback.
- A review-first delivery loop: one PR per job, no auto-merge by default, full audit.
- Not a code runner: Fledge never clones or executes a user repository.
- Not a CI system: it uses the repository's own tests and CI.
- Not an unconditional auto-merge bot: a human (or the repository's own review gate) decides unless a maintainer explicitly enables auto-merge.
- Not a GitHub replacement: it is a thin, auditable layer on top of GitHub.
- GitHub OAuth login with a pending-application gate. The first login sends a
single-use approval email to
admin@hugoxk.online(forwarded to the operator's inbox). Outgoing mail is sent fromfledge@hugoxk.online; user confirmations go to the user's GitHub email. - Admin panel for approve/reject, quota, user activity (last login, repos, jobs), audit and recent jobs. Admin-only; normal users never see it.
- Workspace at
/console: an approved Fledge user gets a focused overview of connected repositories, active jobs and quota, with shortcuts to the full repository list, settings and docs. The shared Portal is linked in the footer; Fledge approval never grants access to other services. - Fork-aware onboarding: enter the upstream repository; Fledge checks for a same-name fork, creates it when needed, keeps issues and PRs on the upstream, and pushes branches to the fork. If you own the upstream, no fork is created.
- Self-selected repository roles: when hosting a repository, choose
maintainerordeveloperbased on your GitHub permission.admin/maintainmay choose either; every other permission can only choosedeveloper. Maintainer unlocks review/maintenance actions and an opt-in auto-merge switch; developer runs iterate/plan jobs only. Roles are per repository and never assigned by a platform admin. Fledge verifies the PR state, check runs and review conclusions before it performs an auto-merge; the agent never merges. - Reviewer role for repository maintainers (
admin/maintain): a scheduled FlyBot reviewer scores every open upstream PR and posts a COMMENT review. Fledge verifies the PR before any maintainer-enabled auto-merge; the reviewer never merges. - Fine-grained GitHub tokens, validated for write access on add, encrypted with AES-256-GCM, and only decrypted for a running job.
- Sessions and CSRF on every browser form; approval links are single-use and expire in 7 days.
- SSRF guard for user model URLs; public endpoints must use HTTPS.
- Redacted logs: no request bodies, no tokens, no full emails.
- One account, many repositories. Each repo has its own goal, cadence (manual, every 15 minutes to every 30 days), enabled flag and last status. The interval is the minimum gap between runs; it does not cap the number of PRs or issues the repository can produce.
- Job lifecycle:
queued → running → succeeded | failed | cancelled | paused | quota_exhausted. - Work items and gates: triage-to-merge work items linked to issues, PRs and jobs; optional plan-first approval with allowed/forbidden paths; per-job pause/resume/cancel; target-branch preflight. An open work item changes what the next scheduled run continues; it never blocks a due repository.
- Continuity across scheduled runs: the next job receives a bounded carry-over block with the last three run digests and open work items. The scheduler prefers finishing or reviewing existing work, and classifies each run as
pr,issue,review,zero,metaorfailed; a meta inventory issue is not counted as product work. - Per-repository FlyBot: each repository gets a separate container, a private bridge/model proxy and a team (Chief, Lead, Product, Test, Security, Reviewer, two Devs). The shared operator FlyBot is never used for user jobs.
- FlyBot bridge: Fledge sends a job descriptor; the agent fetches a scoped GitHub credential, uses a job-scoped model token, opens a PR and calls back with a signature.
- Mock runner for local demos and tests; no network required.
- Timeout and stale-job handling, one active job per repo, a global cap.
- Review at the tip: the required
review-gatecheck reads the newest verdict at the exact head SHA. A T2/T3 change needs a PASS with a realRan:command from a reviewer identity other than the tip author; a new commit voids the PASS. - Risk tiers from the diff: T0/T1 merge on green
ci-ok; T2/T3 need the tip PASS. The tier is computed from every changed path, never from a label. - Opt-in auto-merge: only a maintainer can enable it. Fledge independently verifies the PR is open and mergeable, every required check is green, no review requests changes, the path guard and test evidence pass, and the newest iterate job succeeded before it squash-merges.
- Mechanical releases: the nightly workflow plans the next version, pushes one
release/v<version>branch and opens one mechanical pull request. The first release of an ISO week bumps the minor; later releases in that week bump the patch. After merge, the tag job creates the annotated tag and dispatches the publish run; the release image carries an SBOM and a build-provenance attestation. - Duplicate-work preflight: before an iterate job opens a branch, it checks the upstream open PRs and refuses work already covered by an open pull request.
- Health and readiness:
/healthzreports the version, commit and build time;/readyzreports the database and every per-repository instance. - Metrics and traces: Prometheus
/metrics(bearer token, constant-time compare) and optional OTLP/HTTP traces cover HTTP, jobs, retries, merges, GitHub and the bridge.npm run slo:reportprintsn/afor a quiet window instead of a confident zero. - Alerts and webhook delivery: operational alerts are delivered in-app and to the optional webhook with cooldown dedupe; a failed GitHub webhook delivery is visible in the admin console and can be retried once.
- Backup and restore:
npm run db:backuptakes an online SQLite backup; the restore drill refuses a copy with no application schema and runs in CI on every change. - Instance health and session reconciliation: the health sweep probes DSH
state, restarts an idle instance whose DSH died, recovers a failed instance when DSH answers again, and refreshes stored team session IDs before dispatch. - GitHub API budget: a per-token request budget with
Retry-Afterhandling; webhooks are delivery-deduped.
- 1 CNY initial platform quota per user (
INITIAL_QUOTA_CNY). - OpenAI-compatible gateway at
/v1; cost is read fromx-litellm-response-cost(USD), or estimated from token usage. - A hard HTTP 402
FLEDGE_QUOTA_EXHAUSTEDwith a settings link when the platform quota is gone, plus an in-app notification and at most one email per day. - Own model fallback: any OpenAI-compatible Base URL / Key / Model; saving performs a 1-token test and bypasses the platform quota.
- A per-request
quota_ledgerand an admin-adjustable quota.
flowchart LR
U[User] -->|GitHub OAuth| F[Fledge]
F -->|store token encrypted| DB[(SQLite)]
F -->|validate repo| G[GitHub API]
F -->|enqueue| J[Job queue]
J -->|signed descriptor| B[FlyBot bridge]
B --> A[FlyBot agent]
A -->|GET credential| F
A -->|POST callback| F
A -->|open PR| G
F -->|platform key / own model| M[Model gateway]
M -->|OpenAI compatible| P[Provider / router]
U -->|review| G
- The user signs in and is approved by the administrator.
- They add a repository with a fine-grained token and a goal.
- A manual or scheduled job is created with a job-scoped
flg_token. - The FlyBot agent gets the repo token from a scoped credential URL, uses the model through Fledge's gateway, and opens one PR.
- The agent posts the branch and PR URL back with the job callback secret.
- Fledge records the result, revokes the job token, meters the cost and notifies the user. A human reviews the PR.
Browser ──cookie session──► Fastify (src/app.ts)
├─ SQLite (src/db.ts) users, repos, jobs, quota, audit
├─ GitHub API (src/repos/) validate tokens, PRs
├─ SMTP (src/email/) operator SMTP
├─ /v1 (src/gateway/) per-user quota / own model
└─ jobs (src/jobs/) ──► FlyBot bridge ──► FlyBot agent
Detailed design: docs/architecture.md · trust boundaries: docs/security.md · quota semantics: docs/quota.md.
The user guide and reference live at
https://fledge-docs.hugoxk.online/docs/ (mirrored at
https://hugoxk.online/fledge/docs/). They are built from this repository's
README.md, README.zh.md and docs/ by HugoXK/fledge-docs.
The nightly release routine runs at 22:30 Asia/Shanghai. It plans the next
version, pushes release/v<version> and opens one mechanical pull request. The
first release of an ISO week bumps the minor; every later release in the same
week bumps the patch. After the release PR merges, the tag job writes the
annotated tag and dispatches the publish run; the published image carries an SBOM
and a build-provenance attestation.
README.md, README.zh.md and docs/ are the source for the documentation site.
A release that changes user-facing behaviour updates them in the same pull
request, and the docs site rebuilds from this repository instead of a pinned copy.
Requirements: Node 22.9+ (the app uses node:sqlite) and npm 10+.
git clone https://github.com/HugoXK/fledge.git
cd fledge
npm ci
cp .env.example .env
# Generate the two secrets:
node -e "console.log('SESSION_SECRET='+require('crypto').randomBytes(32).toString('base64'))"
node -e "console.log('TOKEN_ENCRYPTION_KEY='+require('crypto').randomBytes(32).toString('base64'))"
npm run dev
# http://localhost:8080For a local demo without GitHub OAuth, keep DEV_LOGIN_LOGIN=dev in .env and
open http://localhost:8080/auth/dev. A deployed instance without an OAuth App
can use the landing page's GitHub token login; the token only confirms
identity and is never stored. That route is refused when
NODE_ENV=production; the app will not start in production if the variable is
set.
cp .env.example .env
# fill the secrets, OAuth app, SMTP and model settings
docker compose up -d --buildThe image is also published on a tag as
ghcr.io/hugoxk/fledge:<version>.
Create an OAuth app at https://github.com/settings/developers:
- Homepage:
https://fledge.example.com(orhttp://localhost:8080) - Callback:
https://fledge.example.com/auth/github/callback
Default scope: read:user user:email. Users still supply a per-repository
fine-grained token when they add a repo; the OAuth login never needs repo access.
RUNNER_MODE=mock (default) simulates a job without touching a repository. For
real iteration, run the bridge on the FlyBot host:
BRIDGE_TOKEN="$(openssl rand -base64 32)" \
FLYBOT_CHAT_SESSION_ID=session-... \
node bridge/flybot-bridge.mjsThen set RUNNER_MODE=flybot, FLYBOT_BRIDGE_URL and FLYBOT_BRIDGE_TOKEN in
Fledge. See bridge/README.md.
All settings are environment variables; see .env.example for the full list and comments.
| Variable | Default | Meaning |
|---|---|---|
BASE_URL |
http://localhost:8080 |
Public origin for OAuth, cookies and email links |
SESSION_SECRET |
— | Recent random secret; signs CSRF and session values |
TOKEN_ENCRYPTION_KEY |
— | 32-byte base64 key for AES-256-GCM |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET |
— | OAuth App |
ADMIN_GITHUB_LOGIN |
empty | Auto-approved bootstrap super admin; set your own GitHub login |
DEV_LOGIN_LOGIN |
empty | Local demo login; must be empty in production |
MAIL_TRANSPORT |
console |
console writes .eml files; smtp sends |
MAIL_FROM / ADMIN_EMAIL |
fledge@hugoxk.online / admin@hugoxk.online |
Service sender and admin recipient (role aliases) |
INITIAL_QUOTA_CNY |
1 |
Initial platform budget per user |
USD_CNY_RATE |
7.2 |
Conversion for display and enforcement |
RUNNER_MODE |
mock |
mock or flybot |
ALLOW_PRIVATE_MODEL_URLS |
false |
Allow loopback model URLs in development |
Production startup fails closed when the session/encryption keys, OAuth app (or
ALLOW_TOKEN_LOGIN_ONLY=true) or SMTP password are missing.
- New users start with 1 CNY.
- The gateway records the real cost from
x-litellm-response-cost(USD) or estimates it from token usage. - Remaining =
quota_cny - used_usd * USD_CNY_RATE. - At zero: HTTP 402,
code: FLEDGE_QUOTA_EXHAUSTED, a settings link, an in-app notice, and at most one email per day. - If the user configured their own model, the gateway proxies to it and does not touch the platform quota.
The full rules, edge cases and the 402 body are in docs/quota.md.
- AES-256-GCM at rest for GitHub tokens and user model keys.
- HttpOnly/SameSite sessions; CSRF on every form; single-use approval links.
- SSRF checks on user model URLs; public endpoints must use HTTPS.
flg_tokens are hashed, scoped and revocable; job tokens are revoked when the job finishes or times out.- Logs are redacted; request bodies are never logged.
- Security headers (CSP, nosniff, frame deny, HSTS in production).
- No admin merge, no bypass of a required check, and no auto-merge of user PRs unless a maintainer explicitly enables it.
Report a vulnerability privately: see SECURITY.md. The full model is in docs/security.md.
- docs/deploy.md — OAuth, SMTP, nginx, systemd, Docker, backup.
- deploy/ — systemd unit and nginx sample.
npm run db:backup— online SQLite backup (safe while serving).- The service is single-writer SQLite; run one instance per database.
- The FlyBot bridge listens on loopback and should never be public.
- Browser routes and the job credential/callback endpoints: docs/api.md.
- Model gateway: OpenAI-compatible at
${BASE_URL}/v1; authenticate with aflg_token. Example:
curl http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer flg_…" \
-H "Content-Type: application/json" \
-d '{"model":"your-model","messages":[{"role":"user","content":"hi"}],"max_tokens":64}'npm run check # lint + typecheck + tests + build
npm test # the full node:test suite (650+ tests, fake GitHub/model/SMTP)
npm run dev # watch mode
npm run db:backupThe tests use an in-memory SQLite database and local fake servers; no network is
required. CI runs the same commands on Node 22 and 24, builds the Docker image,
audits production dependencies, checks changelog fragments and computes the risk
tier. The required aggregate check is ci-ok.
| Path | What it is |
|---|---|
src/app.ts, src/index.ts |
Fastify app, routes, bootstrap |
src/config.ts, src/db.ts |
Environment loading, SQLite schema/store |
src/auth/, src/users/ |
OAuth, sessions, approvals |
src/repos/ |
GitHub API client, token validation |
src/jobs/ |
Job queue, mock/FlyBot runners |
src/gateway/ |
Model gateway, quota, SSRF guard |
src/email/ |
Console/SMTP mailer, templates |
src/views/, public/ |
Server-rendered UI and assets |
bridge/ |
Bridge for the FlyBot host |
test/ |
Unit and integration tests |
deploy/ |
systemd and nginx samples |
docs/ |
Architecture, API, deploy, quota, security, workflow |
Fledge is developed with the pipeline it describes:
issue → claim → worktree → red test → fix → gates → PR
→ review at the tip → risk tier → merge queue → release
- AGENTS.md — the binding pipeline, tiers, labels and hard rules.
- LESSONS.md — dated lessons; promote after 3 days.
- docs/code-standards.md — Verifier honesty, review format, merge rules.
- docs/autonomous-dev.md — maintenance, claims, release.
The tier is computed from the diff (node scripts/risk-gate.mjs --base origin/main), never from a label. T0/T1 merge on green ci-ok; T2/T3 need a
PASS at the same tip, with a real Ran: command.
| Version | Focus |
|---|---|
v0.1 |
OAuth + approval mail, multi-repo, encrypted tokens, quota gateway, own model, mock/FlyBot runners, admin/audit |
v0.2 |
Per-repo FlyBot teams, goal-specific playbook, team console, fork/reviewer, quota/attribution |
v0.2.1 |
Live SSE console, inline questions, stop/steer, job progress and cost |
v0.2.2 |
Self-selected repository roles, maintainer-gated review and opt-in auto-merge |
v0.2.3 |
Work items, plan approval, upstream preflight, job controls, branch-protection gate, admin support/search, repo budgets, notification webhook |
v0.2.4 |
Provider → models, per-bot models, repository lifecycle, PR delivery, issue commands, live inbox, Product/Test stage sessions |
v0.3 |
Branded per-repo workspace, release automation, tip review gate, operational metrics and alerts (shipped in v0.3.1) |
v0.4 |
Plan-first gates, durable checkpoints, path/approval guards, GitHub App feedback |
v0.5 |
Evidence and learning: job timelines, delivery metrics, shadow evaluation, playbook promotion |
v1.0 |
Postgres option, worker pool, external security review, audit retention |
Full list and open questions: docs/roadmap.md.
Does Fledge push to my default branch?
No. A job creates a branch and one pull request. Fledge never pushes main and
does not merge by default; only a maintainer can opt in to auto-merge.
Where is my GitHub token stored?
Encrypted with AES-256-GCM using TOKEN_ENCRYPTION_KEY; it is decrypted only for
a running job and never rendered back.
What happens when the 1 CNY quota is gone? The gateway returns HTTP 402 and the UI asks you to add your own model API. Jobs stop using the platform key; they continue on your key once configured.
Is the platform itself open source?
Yes, Apache-2.0. The hosted instance at fledge.hugoxk.online is the same code
with the operator's OAuth app and bridge.
Can I self-host it?
Yes. Docker or npm start, a GitHub OAuth app, SMTP, and a FlyBot bridge. See
docs/deploy.md.
Does it support GitLab?
Not in v0.3. The GitHub client is isolated in src/repos/; a second provider is
a roadmap item.
Why node:sqlite?
It removes a native build dependency for a small self-hosted service. The
wrapper is one file (src/db.ts), so a move to Postgres is local.
Contributions are welcome when they follow CONTRIBUTING.md, AGENTS.md and docs/code-standards.md.
- One issue, one branch, one PR. If an issue already has a PR, push there.
- Add a failing test first; list what you ran and did not run.
- Never commit secrets. Never open a public issue with exploit detail.
- User-facing UI text is bilingual Chinese/English; keep both translations and the two READMEs in step.
Apache-2.0. By contributing you agree that your contribution is licensed under the same terms (section 5 of the licence).
Fastify, SQLite, the GitHub API, and FlyBot as the agent runtime.
Fledge / 羽巢 · hosted repositories that grow themselves · hugoxk.online/fledge