new direction

This commit is contained in:
matamune 2026-05-16 03:20:02 +00:00
parent e3e4d1823d
commit 74beb526e9
Signed by: matamune
GPG key ID: 3BB8E7D3B968A324
24 changed files with 795 additions and 397 deletions

View file

@ -1,6 +1,7 @@
# patch.moi
Feed watching and flow dispatch service for upstream project events.
Git-first maintenance control plane for custom patches on top of upstream open
source software.
Canonical public host: `https://patch.moi`.
@ -10,7 +11,12 @@ This is a Bun monorepo:
- `apps/patch`: the Patch service, feed poller, JSONL store, Discord output,
and flow dispatch adapter.
- `docs`: Tome documentation site published under `/docs`.
- `docs`: Tome documentation site for patch.moi.
patch.moi treats Git as the source of truth for maintained projects. Upstream
and fork remotes, patch branches, tags, and commits describe the patch stack.
Patch records update intake, dispatch attempts, and operational history around
those Git facts.
## Endpoints

View file

@ -1,21 +1,91 @@
---
title: Architecture
description: How feeds, targets, state, and flow dispatch fit together.
description: How upstream intake, Git state, forge service mode, workspaces, and release channels fit together.
---
# Architecture
Patch has three runtime pieces:
patch.moi has three product responsibilities:
1. Notice upstream movement.
2. Start or resume the right maintenance workflow.
3. Keep enough durable state to inspect, retry, and review what happened.
The Git repository remains the source of truth for the maintained project.
patch.moi does not replace remotes, branches, tags, commits, or release refs
with a separate project file. It reads those facts and records operational state
around them.
## Runtime Pieces
The current service has these runtime pieces:
- The HTTP server exposes health and admin flow endpoints.
- The feed poller reads configured upstream feeds on an interval.
- The JSONL store keeps feed signals, fork-sync jobs, flow events, and dispatch
outcomes under `DATA_DIR`.
- The JSONL store keeps feed signals, flow events, and dispatch outcomes under
`DATA_DIR`.
- The flow client can execute locally or dispatch to an HTTP flow backend.
The poller does not know how to complete product-specific work. It only turns a
feed entry into a normalized signal and follows the target configured for that
source.
Those pieces are the intake layer. The patch-stack layer can run in local mode
against a checkout, or in service mode through a remote forge workflow and
runner.
Flow targets create a generic `FlowEvent` and use the shared flow client. That
client gives Patch the same contract in local development and in HTTP-backed
service mode.
The first concrete repo to model against is `../codex`. Its maintained branch is
`code-mode-exec-hooks` in the Peezy fork, and the branch carries Code Mode and
Peezy npm release patches ahead of `origin/main`.
## Maintenance Loop
```mermaid
flowchart TD
A["upstream release, tag, or branch update"] --> B["Patch FeedSignal"]
B --> C["durable update event"]
C --> D{"mode"}
D -- local --> E["local Codex workspace"]
D -- service --> R["remote forge workflow"]
R --> S["runner checkout"]
E --> F["rebase or replay patch commits"]
S --> F
F --> G{"conflicts or failing checks?"}
G -- yes --> H["PR, issue, or paused intervention"]
G -- no --> I["candidate branch or tag"]
I --> J["internal build channel"]
I --> K["public release channel"]
```
## Local Mode
In local mode, patch.moi can run inside or next to the maintained repository.
The repository itself describes the project:
- `upstream` or another configured remote points at the source project.
- `origin` or another fork remote points at the maintained fork.
- branch names identify the maintained patch stack and candidate refs.
- tags identify upstream release points and downstream release candidates.
No `.patchmoi` file is required for that topology.
## Service Mode
In service mode, the forge is the coordination surface. For Codex maintenance,
patch.moi should interact with the remote fork host:
- create or update remote maintenance branches
- trigger forge workflows or runners
- open or update pull requests, issues, comments, checks, and artifacts
- record workflow run ids, branch names, and review links
The runner checkout is disposable. The durable project state is the remote fork,
its refs, and the forge records around the maintenance attempt.
For the Codex fork, service mode should be able to target a remote fork, fetch
OpenAI upstream refs in a runner, rebase `code-mode-exec-hooks`, and push a
candidate branch or `rust-v*` tag when policy allows.
See [Forge service mode](forge-service-mode).
## Boundaries
patch.moi owns update intake and maintenance orchestration. Local workspaces or
forge runners own the actual patch application work. Release channels own
deployment and publishing decisions.

View file

@ -0,0 +1,126 @@
---
title: Codex fork model
description: The concrete Git topology patch.moi should learn from the neighboring Codex fork.
---
# Codex Fork Model
The neighboring `../codex` checkout is the concrete model for patch.moi concept
development. It shows why patch.moi should treat Git as the project source of
truth and keep Patch state focused on orchestration.
## Observed Repository
Observed on 2026-05-16:
| Fact | Value |
| --- | --- |
| Checkout | `../codex` |
| Current branch | `code-mode-exec-hooks` |
| Fork remote | `origin` -> `https://github.com/peezy-tech/codex` |
| Branch tracking | `origin/code-mode-exec-hooks` |
| Comparison branch | `origin/main` |
| Patch branch head | `f8594cf39` |
| Candidate tag at head | `rust-v0.130.0` |
| Local working tree | untracked `codex-rs/code-mode/TYPECHECK_PLAN.md` |
There is no `upstream` remote configured in this checkout. That is an important
setup case for patch.moi: the CLI or service should detect it and offer to add
`https://github.com/openai/codex.git` as the upstream remote before running a
release maintenance workflow.
## Patch Stack
The maintained patch stack is the commits on `code-mode-exec-hooks` ahead of
`origin/main`:
```text
5e0d6c54e Expose Code Mode exec to hooks
d715d5829 Add native code mode replay action
a2fb3e6c9 Publish peezy codex npm packages
bc03f1afa Use fork-friendly Peezy npm release workflow
74e1540e1 Increase release build timeout
f8594cf39 Use peezy.tech npm scope
```
Those commits are the patch inventory. patch.moi should not duplicate them in a
project file. It should read them from Git and record the runs that attempted to
carry them forward.
## What This Teaches patch.moi
The Codex fork makes the desired model concrete:
- `origin/main` is a useful local comparison baseline, but a real upstream
remote is still needed for canonical release tags.
- `code-mode-exec-hooks` is the maintained patch branch, but internal use is
not simply "run from this branch."
- `rust-v0.130.0` at the branch head is a downstream candidate or release tag.
- the npm package rename to `@peezy.tech/*` is part of the patch stack, not a
Patch service setting.
- the public release path is encoded in `.github/workflows/rust-release.yml`.
- the internal release surface should build the native binary, place it in the
npm wrapper's local vendor layout, and use a Bun link workflow so the local
`codex` command exercises the same JavaScript launcher path as a release.
- a dirty or untracked working tree should block automated rebases until the
operator decides whether that local work belongs in the patch stack.
## Maintenance Workspace
A patch application workspace for this repo should do the normal Git work:
```bash
cd ../codex
git status --short --branch
git remote get-url origin
git remote get-url upstream || git remote add upstream https://github.com/openai/codex.git
git fetch upstream --tags --prune
git fetch origin --prune
git rev-list --oneline origin/main..code-mode-exec-hooks
```
For an upstream release event, the workspace can resolve the upstream tag,
rebase `code-mode-exec-hooks`, run Codex-specific checks, and push a candidate
branch or tag when policy allows.
In service mode, that work should be triggered through the remote fork host. For
example, patch.moi can create or update a maintenance branch on GitHub, trigger
a runner, and let that runner perform the checkout, rebase, build, and push. The
local `../codex` checkout is a model for topology and local validation, not the
service's durable execution surface.
## Feature Workspace
Feature development should happen in a separate workspace or branch. A new
custom feature starts from the current maintained branch, produces commits, and
only becomes part of the maintained patch stack after it is intentionally merged
or rebased into `code-mode-exec-hooks`.
## Channel Split
The same candidate ref can serve different channels:
| Channel | Codex fork example |
| --- | --- |
| Internal use | build the local native binary, stage it into the npm wrapper/vendor shape, and link that package with Bun |
| Public release | push `rust-v*` tags and let GitHub Actions publish `@peezy.tech/*` packages |
Internal use should be close to the actual release surface without requiring the
full multiplatform CI release. The useful local loop is:
```bash
cd ../codex
# Codex's Rust workspace lives under codex-rs.
(cd codex-rs && cargo build -p codex-cli --bin codex)
mkdir -p codex-cli/vendor/x86_64-unknown-linux-musl/codex
cp codex-rs/target/debug/codex codex-cli/vendor/x86_64-unknown-linux-musl/codex/codex
(cd codex-cli && bun link)
bun link @peezy.tech/codex
codex --version
```
This example shows the x64 Linux wrapper path. The exact target directory,
target triple, and global-versus-project link choice can vary by host and
validation target, but the principle is stable: test the npm wrapper plus native
binary handoff locally, then leave multiplatform artifacts and trusted npm
publishing to CI.

View file

@ -0,0 +1,38 @@
---
title: Codex use case
description: How patch.moi applies to Codex fork maintenance.
---
# Codex Use Case
patch.moi watches GitHub OpenAI Codex branch and release feeds. Branch activity
can notify operators. Release activity can emit a generic `upstream.release`
flow event for codex-flow automation.
The concrete local model is the neighboring `../codex` checkout:
- `origin` points at `https://github.com/peezy-tech/codex`.
- `code-mode-exec-hooks` is the maintained patch branch.
- `origin/main` is the current comparison branch.
- `rust-v0.130.0` is a downstream tag on the maintained branch head.
- the patch stack contains Code Mode exec/replay work and Peezy npm release
changes.
That checkout currently lacks an `upstream` remote, so a patch.moi setup flow
should add or confirm `https://github.com/openai/codex.git` before a release
rebase.
The Codex maintenance flow rebases the Peezy Codex fork patch stack onto a
canonical upstream release tag. That is a patch application workspace, not a
public release by itself.
Internal Codex use can track a fast-moving branch for local work. Public npm
release can follow upstream release tags and trusted publishing. Those channels
should share candidate Git refs when appropriate, but one should not block the
other by default.
In service mode, the same Codex maintenance work can run through a forge runner:
patch.moi creates or updates the remote maintenance branch, triggers the runner,
and records the resulting branch, artifact, check, or PR.
See [Codex fork model](codex-fork-model) for the exact repo-derived model.

View file

@ -1,17 +1,43 @@
---
title: Flow boundary
description: What Patch owns and what codex-flow packages own.
description: What patch.moi owns, what codex-flow owns, and where gateway-style workspace orchestration belongs.
---
# Flow boundary
Patch owns upstream observation. It knows about feeds, source ids, feed state,
and dispatch attempts.
patch.moi owns upstream observation and patch-stack orchestration. It knows
about feed sources, update signals, maintained repositories, remote branches,
workflow runs, dispatch attempts, and operator-visible state.
codex-flow owns execution. Flow packages match `FlowEvent.type` and payload
schema, run Bun or gated Code Mode steps, and emit `FLOW_RESULT`.
codex-flow owns portable event execution. Flow packages match `FlowEvent.type`
and payload schema, run Bun or Code Mode steps, and emit `FLOW_RESULT`.
Product completion stays outside Patch. For example, OpenAI Codex release
automation should decide how to update a fork, open a branch, ask for review, or
publish a result. Patch only dispatches the upstream release event and records
the dispatch outcome.
The boundary should stay narrow:
| Layer | Owns |
| --- | --- |
| patch.moi intake | feeds, source ids, feed state, update records |
| patch.moi orchestration | maintained repo selection, remote branch policy, workflow triggers, retry and review state |
| codex-flow | generic event matching, step execution, run state, `FLOW_RESULT` |
| local workspace or forge runner | git operations, conflict resolution, checks, candidate refs |
| release channel | deploy, publish, trusted publishing, rollback policy |
## Flow Events Are Triggers
A generic `upstream.release` event is a good trigger. It should not become the
whole product model.
patch.moi should be able to say: this upstream release produced this workflow
run, which produced this candidate branch, which was used by this internal build
or public release. A single flow event cannot hold that lifecycle cleanly.
## Service Backend
A patch.moi service backend is useful when patch.moi needs to coordinate a
remote forge, human intervention, and operator surfaces. That backend can own
patch.moi-specific service state while still using codex-flow for generic event
execution where it fits.
The rule is simple: use flow events for portable automation triggers, and use a
patch.moi backend for patch-stack product state: remote refs, workflow runs,
pull requests, issues, checks, artifacts, and review status.

View file

@ -0,0 +1,85 @@
---
title: Forge service mode
description: How patch.moi should coordinate remote fork maintenance through a forge and its runners.
---
# Forge Service Mode
Service mode should be forge-oriented. patch.moi should interact with the
remote Git host for the maintained Codex fork and let that forge hold the
durable coordination surface.
In this mode, patch.moi is not a daemon babysitting one long-lived local clone.
It watches upstream, updates remote refs, opens or updates review surfaces,
triggers workflow runners, and records enough state to inspect what happened.
## Remote Surface
A forge-oriented service can use these remote objects as the product surface:
| Remote object | Purpose |
| --- | --- |
| fork repository | durable maintained project |
| upstream mirror or remote metadata | source of upstream refs and tags |
| patch branch | maintained patch stack |
| maintenance branch | candidate branch for one upstream update |
| pull request or issue | review and operator discussion |
| workflow run | disposable execution workspace |
| artifacts | internal build output and logs |
| checks or statuses | policy gate for landing or publishing |
Git refs and forge records are durable. Runner workspaces are temporary.
## Service Flow
```mermaid
flowchart TD
A["upstream update detected"] --> B["patch.moi records update"]
B --> C["create or update remote maintenance branch"]
C --> D["trigger forge workflow or runner"]
D --> E["runner checks out fork and upstream"]
E --> F["runner rebases patch stack"]
F --> G["runner builds, tests, and writes artifacts"]
G --> H["push candidate ref and report status"]
H --> I["patch.moi updates PR or issue"]
I --> J{"policy allows landing?"}
J -- yes --> K["merge, tag, or publish internal artifact"]
J -- no --> L["wait for review or intervention"]
```
## Codex Fork Shape
For Codex maintenance, patch.moi should treat the remote fork as the service
backend:
- keep `peezy-tech/codex` as the maintained fork repository
- create patch and maintenance branches in that repository
- trigger GitHub Actions or another registered runner
- let the runner create or update patch commits
- publish internal artifacts from runner output when policy allows
- use PRs, issues, comments, checks, and artifacts as the operator surface
The service can still keep its own feed cursor and run index, but the important
project state should be recoverable from the remote forge.
## Difference From Local Mode
Local mode is checkout-oriented. The operator is near the repo and can run,
build, link, inspect, and fix directly.
Service mode is remote-oriented. patch.moi talks to the forge, and the forge
runner creates disposable checkouts to do the work. This keeps service
automation closer to how releases, review, CI, and artifacts already work.
## Codex Runner Role
Codex can participate inside the runner:
- resolve or rebase patch conflicts
- update package metadata
- run project-specific verification
- leave structured failure context for review
- push a candidate branch when allowed
That Codex execution is part of the workflow job. It does not need to be a
long-lived workspace owned by the patch.moi service process.

View file

@ -1,260 +0,0 @@
---
title: Forgejo forking problem space
description: Historical analysis for tracking and possibly forking Forgejo from Patch signals.
---
# Forgejo Forking Problem Space
Date: 2026-05-12
## Current Setup
Created a jojo.build mirror:
- Repo: https://jojo.build/peezy-tech/jojo
- SSH: `ssh://git@jojo.build/peezy-tech/jojo.git`
- Upstream: `https://codeberg.org/forgejo/forgejo.git`
- Default branch: `forgejo`
- Mirror interval: `8h`
This is currently a mirror, not a working fork branch. That is a good starting
point for source inspection and tracking upstream movement. It is not yet a good
place for custom patches, because mirror updates are expected to follow upstream.
## Executive Summary
Forking Forgejo is feasible, but it is not a small maintenance commitment.
Forgejo is a full Go web application with a substantial frontend build,
database migrations, templates, Actions integration, SSH/HTTP Git serving,
packages, OAuth2, and admin surfaces. A fork is reasonable only if the desired
customization cannot be achieved through supported configuration, OIDC, reverse
proxy auth, static assets, or template overrides.
For SIWE specifically, the preferred order remains:
1. Use SIWE through an external OpenID Connect provider.
2. Use a trusted reverse proxy that performs SIWE and passes identity headers.
3. Fork Forgejo only if we need first-class SIWE UX or native account semantics.
## Upstream Release Cadence
Forgejo stable releases are published quarterly. LTS releases are published in
the first quarter of each year and receive critical bugfix/security support for
one year and three months. The current LTS line is v15.0, released 2026-04-16
and supported until 2027-07-15.
Implication: a fork has to either:
- Track every quarterly release and absorb breaking changes often.
- Track only LTS releases and accept slower access to new Forgejo features.
- Track upstream `forgejo` continuously, which maximizes merge churn.
For a production instance, an LTS-based fork is the most conservative option.
## What A Fork Would Own
At minimum, a maintained fork owns:
- A source branch policy.
- CI for Go, frontend, templates, linting, and tests.
- Binary or container image builds.
- A release/version naming scheme.
- Security patch intake.
- Upgrade rehearsals against jojo.build data.
- Documentation for local patches.
- A rollback path to upstream Forgejo.
The risky areas are not only code conflicts. They are also database migrations,
template changes, auth/session behavior, Actions behavior, and generated assets.
## Build And Test Surface
Forgejo source includes:
- `go.mod` for the backend.
- `package.json` and `webpack.config.js` for frontend assets.
- `Makefile` for build/test targets.
- `Dockerfile` and `Dockerfile.rootless`.
- Published release notes in `release-notes-published/`.
Official build docs require Go, Node.js/npm, and `make`. Older docs mention Go
1.22+ and Node 20+, but we should verify exact versions from the branch we pin
before building production artifacts.
Initial local validation target should be:
```bash
make help
make deps-frontend
make frontend
make test
make build
```
Exact target names need confirmation from the current Makefile before scripting.
## Auth Extension Surface
Forgejo has configurable auth sources:
- Local database auth.
- LDAP via BindDN.
- LDAP simple auth.
- SMTP.
- PAM.
- OAuth2.
- OpenID Connect.
- OpenID.
- Reverse proxy header auth.
From source inspection, auth source types are compiled into the application.
OAuth2 providers are registered in Go during init via an internal Goth provider
registry. That registry is useful for patching Forgejo, but it is not an
external plugin API.
Native SIWE would likely require one of these approaches:
- Add a first-class OAuth2/OIDC provider if SIWE is presented as OIDC.
- Add a custom auth flow and routes for EIP-4361 challenge/signature handling.
- Add account-linking fields for wallet addresses and ENS-derived display data.
- Add admin settings and migration(s) if wallet addresses become persisted
first-class identities.
The more native the SIWE behavior, the more the fork touches security-critical
surface: sessions, CSRF, account linking, auto-registration, 2FA bypass rules,
and recovery flows.
## SIWE Fork Design Questions
Before writing code, resolve these:
- Is an Ethereum address the canonical Forgejo username, an external account
identifier, or merely a linked credential?
- Do users need email addresses?
- Can a wallet create a new Forgejo account automatically?
- How are lost wallets handled?
- Can one Forgejo account link multiple wallets?
- Is ENS only display metadata, or does it influence identity?
- Are smart-contract wallets/EIP-1271 required?
- Which chains are accepted?
- Does SIWE bypass local 2FA, complement it, or become a second factor?
- How do Git over HTTPS, SSH keys, access tokens, and API auth map to wallet
sign-in?
These questions matter more than the login button. Forgejo identity is used by
Git, issues, packages, Actions, API tokens, and admin permissions.
## Fork Strategies
### Strategy A: No Fork
Use config, OIDC, reverse proxy auth, and supported UI customization.
Best for:
- Branding.
- Trusted SIWE/OIDC experiment.
- Avoiding security patch ownership.
Risk:
- Less native UX.
- Identity model constrained by Forgejo's existing auth flows.
### Strategy B: Patch Branch On LTS
Create a branch like `jojo/v15.0` from the current LTS tag, maintain a minimal
patch stack, and periodically rebase or merge v15.0 patch releases.
Best for:
- Production stability.
- Small, well-contained changes.
- Predictable security patch intake.
Risk:
- Larger jumps when moving to the next LTS.
- Backport work if desired features land in newer stable releases.
### Strategy C: Patch Branch On Upstream `forgejo`
Maintain `jojo/forgejo` on top of upstream development.
Best for:
- Contributing changes upstream.
- Early access to Forgejo improvements.
Risk:
- Highest churn.
- Bad fit for production unless we have strong CI and staging.
### Strategy D: Hard Product Fork
Rename/rebrand deeply, ship independent releases, and diverge freely.
Best for:
- Building a distinct forge product.
Risk:
- Largest maintenance burden.
- Security, release, migration, and support responsibilities become ours.
This should be avoided unless jojo.build becomes a product-level Forgejo
distribution.
## Recommended Path
Use the mirror as the upstream intake point. Do not customize the mirror branch.
Next create a working fork branch only when we have a concrete patch to test:
- `jojo/v15.0` from the latest v15.0.x tag for production-minded patches.
- `jojo/forgejo` from upstream `forgejo` for exploratory upstreamable patches.
For SIWE, first prototype without a Forgejo fork:
1. Configure a SIWE OIDC provider against a test Forgejo instance.
2. Test user creation, account linking, logout, API tokens, Git over HTTPS, and
SSH key management.
3. Separately test reverse proxy header auth with a toy trusted auth service.
4. Only fork if those approaches fail on essential UX or identity semantics.
## Maintenance Checklist For Any Fork
- Track upstream release notes and security announcements.
- Keep a patch inventory with rationale and owner.
- Rebase/merge upstream into a staging branch first.
- Run full build and test suite.
- Run upgrade rehearsal against a copy of production data.
- Smoke test login, repo browsing, Git SSH, Git HTTPS, Actions, packages,
mirrors, and admin pages.
- Keep a rollback artifact for the previous known-good binary/container.
- Document every app.ini setting required by the fork.
## Open Questions
- Is jojo.build currently installed from binary, container, package manager, or
local build?
- How is production deployment currently rolled out and rolled back?
- Do we want custom patches to be private indefinitely, or upstreamable?
- Would SIWE be required for all users, optional, or only for selected orgs?
- Is the target experience "login with wallet" or broader onchain identity?
- Are we willing to run an external IdP such as a SIWE OIDC provider?
## Sources Consulted
- Forgejo mirror created from `https://codeberg.org/forgejo/forgejo.git`.
- Forgejo auth docs: https://forgejo.org/docs/v11.0/user/authentication/
- Forgejo OAuth2 provider docs: https://forgejo.org/docs/v13.0/user/oauth2-provider/
- Forgejo customization docs: https://forgejo.org/docs/next/admin/advanced/customization/
- Forgejo config cheat sheet: https://forgejo.org/docs/latest/admin/config-cheat-sheet/
- Forgejo upgrade guide: https://forgejo.org/docs/next/admin/upgrade/
- Forgejo release schedule: https://forgejo.org/docs/v11.0/admin/release-schedule
- Forgejo compile-from-source docs: https://forgejo.org/docs/v7.0/developer/from-source/
- SIWE docs: https://docs.siwe.xyz/
- SIWE hosted OIDC docs: https://docs.login.xyz/servers/oidc-provider/hosted-oidc-provider

View file

@ -0,0 +1,107 @@
---
title: Git source of truth
description: Why patch.moi uses remotes, branches, tags, and commits as the project model.
---
# Git Source Of Truth
patch.moi should not invent a second project format for patch stacks. The
maintained repository is already the best source of truth:
- remotes say where upstream and the maintained fork live
- branches say which patch stack is being maintained
- tags say which upstream or downstream release point is being targeted
- commits are the patch inventory
- worktrees, checkouts, and runner workspaces are disposable execution surfaces
This matters because patch.moi is meant to maintain open source forks, not hide
them behind an application database.
## Required Facts
A maintained project needs these facts to be discoverable from Git:
| Fact | Typical expression |
| --- | --- |
| Upstream project | `upstream` remote |
| Maintained fork | `origin` remote |
| Upstream release point | upstream tag or branch |
| Patch stack | commits on a maintained branch ahead of upstream |
| Candidate output | downstream branch or tag |
Names can be configured by the operator or service, but the facts should still
resolve to Git refs.
## What patch.moi Stores
patch.moi stores operational state:
- feed cursors
- normalized upstream signals
- dispatched flow events
- dispatch outcomes
- workspace run status
- retry and replay history
- operator-facing notes or intervention state
That state explains what happened. It is not the patch stack itself.
## Local Mode
When patch.moi runs locally, the current checkout can be the project model. The
CLI or service process should inspect remotes and branches, then add missing
remotes only when the operator confirms or supplied enough information.
The default happy path is:
```bash
git remote get-url upstream
git remote get-url origin
git branch --show-current
git fetch upstream --tags --prune
```
If the upstream remote is missing, patch.moi can help add it. If the fork remote
is missing, patch.moi can help point `origin` or another chosen remote at the
maintained fork.
A cloned GitHub fork commonly starts with only `origin` set to the user's fork.
That is a valid initial shape. patch.moi can use provider metadata to discover
the parent repository, then materialize that discovery into Git by adding an
`upstream` remote and fetching tags.
The neighboring Codex fork demonstrates this exact case. `../codex` has
`origin` set to `https://github.com/peezy-tech/codex` and a maintained
`code-mode-exec-hooks` branch, but no `upstream` remote. patch.moi should infer
the patch stack from Git and treat the missing upstream remote as setup work.
See [Codex fork model](codex-fork-model) for the concrete topology.
## Service Mode
When patch.moi runs as a service, the remote forge becomes the durable
coordination surface. The service should talk to remote repositories, branches,
pull requests, issues, workflow runs, checks, and artifacts.
Runner checkouts are disposable. A workflow can clone the fork, fetch upstream,
rebase the patch stack, build artifacts, push a candidate branch, and disappear.
The important rule stays the same: pushed refs and forge records are durable
truth; runner workspace state is temporary execution state.
See [Forge service mode](forge-service-mode).
## Policy That Is Not In Git
Some policy cannot be inferred from refs alone:
- which feed to watch
- which branch should receive patch-stack updates
- which checks are required before a candidate is usable
- which ref supplies the internal build/link workflow
- which forge workflow or runner should apply patches
- whether public release uses GitHub trusted publishing
That policy can live in service configuration, environment, codex-flow config,
or existing repo-native files such as `package.json`, CI workflows, `Makefile`,
or release docs. It should not obscure where the patch stack actually lives.

View file

@ -1,25 +0,0 @@
---
title: Upstream use cases
description: How Patch is used for Forgejo and Codex upstream tracking.
---
# Upstream use cases
## Forgejo
Patch watches Codeberg Forgejo branch and release feeds. Branch activity can be
notification-only. Release activity can still produce a legacy `fork_sync` job
for a jojo-hosted Forgejo fork workflow.
The Forgejo fork remains a maintenance decision outside Patch. Patch records the
upstream signal and job; fork policy, branch policy, CI, and release ownership
belong to the Forgejo fork process.
## OpenAI Codex
Patch watches GitHub OpenAI Codex branch and release feeds. Branch activity can
notify operators. Release activity emits a generic `upstream.release` flow event
for codex-flow automation.
This keeps the release feed integration stable while the actual Codex release
automation evolves in flow packages and backends.

View file

@ -0,0 +1,110 @@
---
title: Workspaces and channels
description: How update scanning, patch application, feature development, internal builds, and public releases differ.
---
# Workspaces And Channels
patch.moi has to keep several concepts separate. They often touch the same Git
repository, but they should not collapse into one process.
## Update Feed
The update feed watches upstream. It answers one question:
> Did upstream move in a way we care about?
That can be a release tag, a branch update, a security advisory, or another
source signal. The feed should create durable update records and then stop. It
does not decide how to deploy or publish the maintained fork.
## Patch Application Workspace
A patch application workspace is the disposable place where a specific upstream
point is carried forward into the maintained patch stack. In local mode, that
can be a Codex workspace near the checkout. In service mode, it should usually
be a forge runner checkout.
Typical work:
- fetch upstream and fork remotes
- resolve the upstream target tag or commit
- rebase, merge, or cherry-pick the patch stack
- stop on conflicts with useful context
- run verification commands
- produce a candidate branch or tag
The workspace may be local or runner-managed. The patch stack itself still lives
in Git.
In the current Codex fork, this means carrying the commits on
`code-mode-exec-hooks` ahead of `origin/main` onto a canonical upstream release
tag from `openai/codex`.
## Feature Development Workspace
A feature development workspace creates new patch commits. It is not the same as
the maintenance workspace or runner job.
Feature work can start from the current maintained branch, produce commits, and
push them to a patch branch or pull request. Once merged into the maintained
patch stack, those commits become part of future maintenance runs.
Keeping feature development separate prevents a new feature from being confused
with the automated task of carrying existing patches onto a new upstream point.
## Internal Build Channel
The internal channel is for immediate use by the operator. For example:
- a local Codex fork can build and link the native binary through the npm wrapper
- a runner can publish internal Codex artifacts from a maintenance branch
- internal containers or binaries may be produced before public release
This channel can track upstream main, a release candidate branch, or any other
operator-chosen ref. It should not be blocked by public release mechanics unless
the operator wants that coupling.
For the Codex fork, the internal channel should build the local native binary,
stage it into the npm wrapper/vendor layout, and link that package with Bun.
That tests the same JavaScript launcher and binary handoff users get from npm
without waiting for the full multiplatform CI release.
In service mode, the same idea should happen through a forge runner artifact:
the runner builds the binary, stages the wrapper shape, and publishes an
internal artifact or package without invoking the whole public release workflow.
## Public Release Channel
The public release channel is for artifacts other people consume. It usually has
stricter rules:
- follow upstream release tags
- run reproducible CI checks
- publish from the public repository
- use GitHub Actions or another trusted publishing path for npm
- keep release notes and versioning stable
Public release can take longer than internal use. A clean architecture lets
internal builds move while public release waits for review, CI, or upstream
release cadence.
For the Codex fork, public release is the `rust-v*` tag path in GitHub Actions
that publishes the `@peezy.tech/*` npm packages. That path should remain
separate from local use of the fork.
## Why This Split Matters
The same upstream signal may fan out to multiple outcomes:
```mermaid
flowchart LR
Update["upstream update"] --> Apply["patch application workspace"]
Apply --> Candidate["candidate ref"]
Candidate --> Internal["internal build"]
Candidate --> Public["public release"]
Candidate --> Feature["future feature branch base"]
```
patch.moi should record the relationship between those outcomes without forcing
one channel to depend on another.

View file

@ -1,6 +1,6 @@
---
title: Configure feed sources
description: Add upstream feeds and choose notification, fork-sync, or flow targets.
description: Add upstream feeds and route update signals into patch maintenance work.
---
# Configure feed sources
@ -8,6 +8,9 @@ description: Add upstream feeds and choose notification, fork-sync, or flow targ
Feed sources live in a JSON file referenced by `FEED_SOURCES_PATH`. The bundled
file is `apps/patch/feed-sources.json`.
Feed sources describe intake. They should not duplicate the maintained patch
stack. The patch stack lives in Git as remotes, branches, tags, and commits.
## Choose an event
Use `event: "push"` for branch commit feeds and `event: "release"` for release
@ -15,7 +18,7 @@ feeds. Patch normalizes both into `FeedSignal` records.
## Choose a target
`notify_only` stores the signal and can notify Discord:
`notify_only` stores the signal without dispatching patch work:
```json
{
@ -26,17 +29,6 @@ feeds. Patch normalizes both into `FeedSignal` records.
}
```
`fork_sync` stores a legacy fork-sync job for release entries:
```json
{
"provider": "jojo",
"repoFullName": "peezy-tech/jojo",
"branch": "forgejo",
"mode": "fork_sync"
}
```
`flow_dispatch` creates a generic `FlowEvent` and dispatches it:
```json
@ -51,5 +43,9 @@ feeds. Patch normalizes both into `FeedSignal` records.
}
```
For patch-stack maintenance, prefer `flow_dispatch` to create an
`upstream.release` or `upstream.update` trigger. Let the receiving workspace read
Git to discover the maintained patch branch and candidate refs.
Set `primeOnly: false` only when old feed entries should be emitted on the first
poll.

View file

@ -1,20 +0,0 @@
---
title: Enable Discord output
description: Send selected upstream signals to a Discord webhook.
---
# Enable Discord output
Discord notifications are disabled by default.
```bash
DISCORD_OUTPUT_ENABLED=true
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
DISCORD_NOTIFY_EVENTS=push,release
```
`DISCORD_NOTIFY_EVENTS` is a comma-separated allow list. Patch still stores feed
signals when Discord is disabled or when an event is not in the allow list.
Notifications include provider, repository, event type, branch, author, short
SHA, queued job kind, and source id when those fields are available.

View file

@ -1,6 +1,6 @@
---
title: Run Patch locally
description: Install dependencies, start the service, and run checks.
description: Install dependencies, inspect the Git project model, start the service, and run checks.
---
# Run Patch locally
@ -11,6 +11,29 @@ Install from the repository root:
bun install
```
Inspect the maintained repository you want patch.moi to operate around. The
repo should expose its upstream and fork as Git remotes:
```bash
git remote -v
git branch --show-current
git status --short --branch
```
The usual local shape is:
| Git fact | Meaning |
| --- | --- |
| `upstream` remote | source project |
| `origin` remote | maintained fork |
| current branch | patch stack or candidate branch |
| upstream tag | release point to rebase onto |
If `upstream` is missing, the repo may still be valid. A common GitHub flow is
fork in the web UI, then clone your own fork, which gives you only `origin`.
patch.moi should discover the parent repository from provider metadata when it
can, then add and fetch the upstream remote.
Start the service app:
```bash
@ -33,3 +56,11 @@ DATA_DIR=./data FEED_SOURCES_PATH=./feed-sources.json bun run dev
```
`GET /healthz` returns `ok` when the server is running.
Local flow dispatch runs from the process working directory when
`PATCH_FLOW_DISPATCH_URL` is unset. That makes local mode useful for testing a
patch application workspace before sending the same event to a service backend.
Local mode is checkout-oriented. Service mode is forge-oriented: patch.moi
should talk to the remote forge, trigger a runner, and let that runner perform
the disposable checkout and patch application work.

View file

@ -1,48 +1,60 @@
---
title: patch.moi
description: Feed watching and flow dispatch for upstream project events.
description: Hands-off maintenance for custom patches on top of upstream open source software.
---
# patch.moi
Patch is a small Bun service that watches upstream Atom/RSS feeds and turns
selected upstream activity into durable Patch records, Discord notifications,
or generic codex-flow events.
patch.moi keeps custom features alive on top of upstream open source projects.
It watches upstream movement, records durable update signals, and hands the
actual patch work to local workspaces or remote forge runners that operate on
normal Git repositories.
The service keeps the product boundary narrow:
The product boundary is Git-first:
- Feeds describe upstream repositories and events.
- Patch normalizes feed entries into `FeedSignal` records.
- Targets decide whether a signal is notification-only, a legacy fork-sync job,
or a generic flow dispatch.
- Flow dispatch uses `@peezy.tech/flow-runtime/client` so Patch can run flows
locally during development or send events to an HTTP backend in service mode.
- Admin endpoints inspect stored flow events and dispatch records, then retry or
replay events when an upstream automation needs another attempt.
- Upstream projects stay upstream remotes, tags, branches, and release feeds.
- Maintained forks stay fork remotes and patch branches.
- Patch stacks are commits, branches, and tags, not a second Patch-specific
project file.
- patch.moi records observations, dispatch attempts, workflow runs, and review
state around those Git facts.
- Local Codex workspaces or forge runners do the maintenance work: rebase patch
commits, resolve conflicts, build candidates, and leave human intervention
points when needed.
```mermaid
flowchart LR
Feed["Atom or RSS feed"] --> Patch["Patch poller"]
Patch --> Signal["FeedSignal JSONL"]
Signal --> Notify["Discord output"]
Signal --> Job["fork_sync job JSONL"]
Signal --> Event["FlowEvent JSONL"]
Event --> Client["flow-runtime client"]
Client --> Local["local flow execution"]
Client --> Backend["HTTP flow backend"]
Upstream["upstream repo"] --> Feed["release and branch feeds"]
Upstream --> Git["upstream remote"]
Fork["maintained fork"] --> Git
Feed --> Patch["patch.moi intake"]
Patch --> Event["durable update signal"]
Event --> Workspace["local workspace or forge runner"]
Git --> Workspace
Workspace --> Candidate["remote candidate branch, tag, or artifact"]
Candidate --> Internal["internal build channel"]
Candidate --> Public["public release channel"]
```
## Start here
- New service setup: [Watch an upstream release](tutorials/watch-upstream-release).
- Codex release automation: [Dispatch a Codex release flow](tutorials/dispatch-codex-release-flow).
- Codex patch-stack automation: [Dispatch a Codex release flow](tutorials/dispatch-codex-release-flow).
- Running the service: [Run Patch locally](guides/run-patch-locally).
- Git model: [Git source of truth](concepts/git-source-of-truth).
- Concrete Codex model: [Codex fork model](concepts/codex-fork-model).
- Service mode: [Forge service mode](concepts/forge-service-mode).
- Release channels: [Workspaces and channels](concepts/workspaces-and-channels).
- Exact feed shape: [Feed sources](reference/feed-sources).
- Admin operations: [HTTP API](reference/http-api).
## What is in this repo
- `apps/patch`: the Patch Bun service, feed poller, JSONL store, Discord output,
and flow dispatch adapter.
- `apps/patch`: the Patch Bun service, feed poller, JSONL store, and flow
dispatch adapter.
- `docs`: this Tome documentation site, organized with the Diataxis framework.
- `Dockerfile`: container image for the Patch service app.
The current service implements upstream intake and dispatch. Patch-stack
maintenance is performed by the local workspace, forge runner, or codex-flow
package that receives the event.

View file

@ -1,9 +1,9 @@
---
title: Dispatch and replay flow events
description: Use local or HTTP flow execution and retry stored events.
title: Flow event retry and replay
description: Reference for local or HTTP flow execution and retrying stored update triggers.
---
# Dispatch and replay flow events
# Flow Event Retry And Replay
Patch creates deterministic event ids:
@ -14,6 +14,10 @@ patch:<sourceId>:<entryId>:<eventType>
Dispatch is idempotent at the flow backend by event id. Replay intentionally
asks the backend to create another attempt for the stored event.
For patch-stack maintenance, treat the event as an update trigger. The
authoritative patch state still comes from Git when the local workspace or forge
runner runs.
## Select HTTP dispatch
```bash
@ -39,3 +43,7 @@ curl -X POST http://127.0.0.1:3000/flow-events/<event-id>/replay
`retry` dispatches the stored event again. `replay` calls the backend replay
endpoint when HTTP mode is configured, or dispatches locally when no backend URL
is configured.
Retrying or replaying an event should not rewrite patch branches by itself. The
workspace or flow package decides whether to push candidate refs after it checks
the current Git state.

View file

@ -1,6 +1,6 @@
---
title: Environment
description: Runtime environment variables used by Patch.
description: Runtime environment variables used by patch.moi.
---
# Environment
@ -15,11 +15,14 @@ description: Runtime environment variables used by Patch.
| `PATCH_FLOW_DISPATCH_URL` | unset | Default flow backend URL for dispatch targets. |
| `PATCH_FLOW_BACKEND_URL` | unset | Alternate default backend base URL. |
| `PATCH_FLOW_DISPATCH_SECRET` | unset | HMAC secret for HTTP flow dispatch. |
| `DISCORD_OUTPUT_ENABLED` | `false` | Enables Discord webhook output. |
| `DISCORD_WEBHOOK_URL` | unset | Discord webhook target. |
| `DISCORD_NOTIFY_EVENTS` | `push,release` | Comma-separated notification allow list. |
| `CODEX_APP_SERVER_CODEX_COMMAND` | unset | Passed to local code-mode flow execution. |
| `CODEX_HOME` | unset | Passed to local code-mode flow execution. |
Feed target fields can override backend settings with `dispatchUrl`,
`dispatchUrlEnv`, and `dispatchSecretEnv`.
Git topology is intentionally not represented here. Local mode should read
upstream, fork, branch, and tag state from Git. Service mode should read remote
repository, branch, workflow, and review state from the forge. Environment
variables should stay limited to runtime concerns such as dispatch URLs, data
directories, and Codex execution settings.

View file

@ -1,16 +1,20 @@
---
title: Feed sources
description: JSON schema by convention for upstream feed configuration.
description: JSON schema by convention for upstream update intake.
---
# Feed sources
`FEED_SOURCES_PATH` points at a JSON object with a `sources` array.
This file configures update intake, not the patch stack. A flow target can add
payload hints, but the receiving workspace should use Git remotes, branches, and
tags as the maintained project source of truth.
```ts
type FeedSourceConfig = {
id: string;
provider: "codeberg" | "github" | "jojo";
provider: "github";
url: string;
event: "push" | "release";
repo: {
@ -20,7 +24,7 @@ type FeedSourceConfig = {
webUrl: string;
defaultBranch?: string;
};
target?: FeedForkSyncTarget | FeedFlowDispatchTarget;
target?: FeedFlowDispatchTarget;
pollIntervalSeconds?: number;
primeOnly?: boolean;
};
@ -42,3 +46,7 @@ type FeedFlowDispatchTarget = {
The flow payload includes provider, event, source id, entry id, title, URL,
author, published time, repository fields, ref, SHA, tag, and raw feed metadata.
Values from `target.payload` are merged last.
For release maintenance, use a stable event type such as `upstream.release` and
include only routing hints in `payload`. Avoid copying branch topology into the
feed source when it can be read from the repository.

View file

@ -1,6 +1,6 @@
---
title: HTTP API
description: Health, flow event inspection, retry, replay, and dispatch history.
description: Health, update-trigger inspection, retry, replay, and dispatch history.
---
# HTTP API
@ -25,6 +25,9 @@ POST /flow-events/:id/replay
The list endpoint returns stored events newest first. The detail endpoint
returns the event and matching dispatch records.
These endpoints inspect update triggers and dispatch attempts. They do not
inspect or modify Git patch stacks directly.
## Dispatches
```text

View file

@ -1,19 +1,24 @@
---
title: JSONL state
description: Files written under DATA_DIR.
description: Operational records written under DATA_DIR.
---
# JSONL state
Patch uses append-only JSONL files for durable service records.
Patch uses append-only JSONL files for durable service records. These files are
operational state. They are not the patch stack.
| File | Contents |
| --- | --- |
| `feed-state.json` | Per-source last seen entry and last checked timestamp. |
| `feed-events.jsonl` | Normalized `FeedSignal` records. |
| `feed-jobs.jsonl` | Legacy `fork_sync` jobs emitted from release signals. |
| `flow-events.jsonl` | Generic `FlowEvent` records emitted by flow targets. |
| `flow-dispatches.jsonl` | Dispatch, retry, replay, and failure records. |
Admin endpoints read `flow-events.jsonl` and `flow-dispatches.jsonl`. The feed
poller appends to all relevant files as it accepts new feed entries.
If a runner checkout is lost, patch.moi should be able to recreate the
maintenance context from remote Git refs and forge records. JSONL state explains
feed and dispatch history; Git and the forge remain the source of truth for
patch contents and review state.

View file

@ -1,6 +1,6 @@
---
title: Packages
description: Workspace packages in the Patch monorepo.
description: Workspace packages in the patch.moi monorepo.
---
# Packages
@ -15,10 +15,12 @@ Responsibilities:
- Poll configured feeds.
- Normalize entries into `FeedSignal` records.
- Store JSONL state.
- Emit optional Discord notifications.
- Dispatch generic codex-flow events through `@peezy.tech/flow-runtime/client`.
- Serve admin inspection, retry, and replay endpoints.
The service package does not store patch contents. Maintained patch stacks live
in Git repositories operated on by local workspaces or forge runners.
## `@peezy.tech/patch-docs`
The Tome documentation package in `docs`. Build it with:

View file

@ -1,12 +1,13 @@
---
title: Dispatch a Codex release flow
description: Connect the OpenAI Codex release feed to codex-flow automation.
description: Connect the OpenAI Codex release feed to a Codex patch-stack maintenance workspace.
---
# Dispatch a Codex release flow
Patch was built to let upstream release activity trigger generic codex-flow
automation without putting Codex-specific completion logic into Patch itself.
This tutorial connects upstream OpenAI Codex releases to the Codex fork
maintenance flow. The flow rebases a maintained patch stack onto an upstream
release tag and verifies the candidate.
## 1. Use the release source
@ -14,6 +15,24 @@ The bundled `apps/patch/feed-sources.json` includes
`github-openai-codex-releases`. Its target emits `upstream.release` events with
the upstream repository and release tag in the payload.
The maintained Codex fork should still be modeled in Git. In the neighboring
`../codex` checkout, `origin` is `https://github.com/peezy-tech/codex` and
`code-mode-exec-hooks` is the maintained patch branch.
Before running release maintenance, make sure the checkout has a canonical
upstream remote:
```bash
cd ../codex
git remote get-url upstream || git remote add upstream https://github.com/openai/codex.git
git fetch upstream --tags --prune
git fetch origin --prune
git status --short --branch
```
If `git status` shows local changes or untracked files, resolve them before an
automated rebase.
## 2. Point Patch at a backend
```bash
@ -38,7 +57,26 @@ or `X-Patch-Admin-Token: <token>`.
## 4. Keep completion app-owned
Patch dispatches the generic event. The installed Codex release flow owns the
work that happens next: matching `flow.toml`, running steps, checking gates, and
emitting `FLOW_RESULT`. Product-specific completion stays in that flow package
or its backend worker.
Patch dispatches the generic event. The installed Codex release flow or
workspace owns the work that happens next:
- fetch upstream tags
- resolve the release tag
- rebase the maintained patch branch
- collect conflict context when the rebase stops
- run the configured checks
- optionally push a candidate ref
That candidate can be used for an internal build/link workflow before a public
release exists: build the local native binary, place it in the npm wrapper's
vendor layout, and link the package with Bun. Public npm publishing should stay
a separate channel because it may need GitHub Actions, trusted publishing,
release review, and upstream schedule alignment.
For the current Codex fork, public release is the `rust-v*` tag workflow that
publishes the `@peezy.tech/*` npm packages.
In service mode, patch.moi should trigger this work through the remote forge
instead of depending on a persistent local checkout. The service creates or
updates a maintenance branch, starts a runner workflow, and records the PR,
issue, check, artifact, or candidate ref that the runner produces.

View file

@ -1,12 +1,22 @@
---
title: Watch an upstream release
description: Configure a release feed and store the first Patch flow event.
description: Configure a release feed and turn an upstream release into patch maintenance input.
---
# Watch an upstream release
This tutorial creates the smallest useful release watcher: one upstream release
feed that becomes a stored `upstream.release` flow event.
This tutorial creates the smallest useful patch.moi intake: one upstream release
feed that becomes a stored update signal. That signal can later start a Codex
workspace that rebases a patch stack.
Before configuring the feed, make sure the maintained repository has a Git
source of truth:
```bash
git remote get-url upstream
git remote get-url origin
git status --short --branch
```
## 1. Add a feed source
@ -42,7 +52,10 @@ Create or edit `apps/patch/feed-sources.json`:
}
```
## 2. Start Patch
The target emits a generic `upstream.release` event. The event is a trigger for
patch work; the patch commits still live in the maintained Git repository.
## 2. Start patch.moi
```bash
DATA_DIR=./data \
@ -63,3 +76,17 @@ When the feed later contains an unseen release entry, Patch appends:
If `PATCH_FLOW_DISPATCH_URL` is not set, Patch uses local flow execution from
the working directory. If it is set, Patch sends the event to the HTTP backend.
## 4. Connect patch work
A matching codex-flow package or backend workspace can consume the
`upstream.release` event and run the maintenance loop:
1. fetch upstream tags
2. resolve the release tag
3. rebase or replay patch commits
4. stop for conflicts or failing checks
5. push a candidate branch or tag when policy allows
Internal builds and public release jobs can then consume the candidate ref
independently.

View file

@ -1,7 +1,7 @@
/** @type {import('@tomehq/core').TomeConfig} */
export default {
name: "patch.moi",
basePath: "/docs",
basePath: "/",
theme: {
preset: "editorial",
mode: "auto",
@ -21,8 +21,6 @@ export default {
pages: [
"guides/run-patch-locally",
"guides/configure-feed-sources",
"guides/dispatch-and-replay-flow-events",
"guides/enable-discord-output",
],
},
{
@ -31,6 +29,7 @@ export default {
"reference/environment",
"reference/feed-sources",
"reference/http-api",
"reference/dispatch-and-replay-flow-events",
"reference/jsonl-state",
"reference/packages",
],
@ -39,9 +38,12 @@ export default {
group: "Concepts",
pages: [
"concepts/architecture",
"concepts/git-source-of-truth",
"concepts/codex-fork-model",
"concepts/forge-service-mode",
"concepts/workspaces-and-channels",
"concepts/flow-boundary",
"concepts/upstream-use-cases",
"concepts/forgejo-forking-problem-space",
"concepts/codex-use-case",
],
},
],

View file

@ -1,7 +1,7 @@
{
"name": "patch-moi",
"version": "0.1.0",
"description": "Feed watching and flow dispatch service for patch.moi.",
"description": "Git-first maintenance control plane for upstream patch stacks.",
"private": true,
"type": "module",
"packageManager": "bun@1.3.11",