Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Code Factory contributor instructions

Develop on dedicated branches and submit changes through pull requests. Do not
commit or push development changes directly to main unless explicitly requested.
Run required checks and review before merging; merge only when requested.

Use the [layered specification guide](docs/specs/README.md) and
[reconciliation skill](.agents/skills/reconcile-specs/SKILL.md) for source, tests
and behavior changes. Preserve glossary → meaning, UI → glossary, and flows →
Expand Down
37 changes: 36 additions & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,45 @@ A prepared launch is immutable. The Start transaction requires prepared state; a

Question IDs are service-generated and map to the original process request ID. Answers require a matching live request and permitted choices/schema. The service durably claims a request before sending its response. A process failure in that window may lose delivery; the response is never replayed. Original worktrees and history remain available for explicit recovery. Notification of a resolved request invalidates it across all views.

The app-server connection/process belongs to the daemon, not to an MCP request or UI frame. Every run receives its own worktree. The client uses the installed Codex 0.161.0 protocol, checks the version before launching, and lets Codex enforce managed requirements. Background inference uses a separate ephemeral read-only thread, disables external tools/apps through config overrides, rejects requests, and yields to manual work.
The app-server connection/process belongs to the daemon, not to an MCP request or UI frame. Every run receives its own worktree. The client uses the installed Codex app-server protocol with a stable 0.161.0 minimum, checks the version before launching, and lets Codex enforce managed requirements. Managed upgrades use the owner-selected dkropachev/codex fork and require a compatibility probe before provider activation. Background inference uses a separate ephemeral read-only thread, disables external tools/apps through config overrides, rejects requests, and yields to manual work.

Publishing settings become developer instructions for the agent. The service cannot independently police every external operation performed by arbitrary tools; sandbox/approval policy and credentials define the execution boundary. A future host adapter must not reinterpret a profile to weaken it.

PR review preparation rejects the signed-in account’s own PR and unknown author/identity. Both launch entrypoints share the guard; atomic Start checks retained proposals and fresh source checks repeat it before execution. Prepared runs retain review intent across default-profile changes. Other work on an own PR remains permitted.

## Work projections and question recovery

Queue membership is a server projection, shared by snapshots and filtered inbox calls. Started runs track an item independently of runtime completion. A closed/merged PR leaves Working; a closed issue or merged explicitly associated implementation PR completes issue work. Reopening restores eligible work. Manual associations and GitHub development links carry implementation intent; source references retain evidence without acquiring that intent. Item activity aggregates all sessions so an older blocker remains visible.

PR lifecycle, review and CI are independent typed values. Read-only GraphQL metadata provides current-head rollups and development links; latest opinionated reviews supply approval information when a repository has no authoritative review decision. Referenced PRs are fetched individually without configuring their repositories. Poll freshness and synchronization errors do not change content revisions. Failed metadata refresh preserves same-head results and development links; a changed head cannot inherit old CI success.

Questions have RPC, structured-message or textual origins. Only RPC origins carry live process request IDs. Message/text answers durably claim the attention before steering or restoring the original session; uncertain delivery is not automatically replayed. Synthetic answers retain encrypted redaction values before delivery. Lost native questions can become textual continuations, while approvals must regain a native authorization request.

Synthetic questions are reconciled individually after delivered messages, turn completion and startup. A read-only helper sees bounded redacted same-run owner/agent conversation, identifies only explicit decisions followed by acknowledgements, and must return exact evidence references and quotes. Validation rejects invented IDs/quotes, wrong event order and concurrent conversation changes. Only settled questions are removed from actionable parameters; their resolution metadata references the retained source journal. Other questions retain their original IDs and fields. Native approvals/RPCs are excluded. Completion, progress, delivery acceptance and other-run publication alone cannot settle a question. Uncertainty preserves the ask; saved-state reads never invoke this helper.

A recovery episode is keyed by run and source turn, with durable stage and at most two claimed repair attempts. Its helper uses bounded redacted context, an ephemeral read-only thread, disabled external MCP/apps and a supported low reasoning effort. Repair turns use question-only Plan mode in the original thread and retain its sandbox, approval and publishing authority. Successful answers finish that question-only turn before an ordinary continuation explicitly restores the profile mode. User takeover cancels further repair; process loss retains the episode without replay. The console displays the same redacted journal and uses existing message, answer and interrupt operations. Journal metadata identifies daemon-generated repair and continuation input by its turn and exact text, preserving the role of real answers in that same turn.

## GitHub source and cache

Application code accepts a `GitHubSource` interface. `CachedGitHub` implements
that same read API around the existing budgeted HTTP/GraphQL adapter. Query
identity includes endpoint/principal scope, operation and arguments. Normal
reads reuse successful unexpired values; misses and invalidations fetch fresh
remote data. Cached summaries retain their summary-only import semantics and
actual provider observation timestamps. Cached values never share mutable
storage with callers. Incomplete enrichment and failures are not cached as
successes. Private persistent entries and in-memory operation use bounded caches.

Freshness is an explicit context choice. Execution preflight, notification-driven
review-target verification, post-turn publication observation and manual polling
request live reads through the same API. Live reads bypass all TTLs, use the
existing conditional validators and quota gate, then update the query cache.
They invalidate related item/repository snapshots so subsequent ordinary reads
can observe the newly verified source. Failed live validation never falls back
to a saved success. Scoped invalidation serializes against in-flight fills;
cache hits do not wait behind network requests. Authentication changes during
a fetch reject its result instead of caching it under the wrong principal.

## Host boundary

HTTP is loopback-only and bearer-authenticated. The tunnel's stdio proxy reads the token locally and forwards MCP requests and required version-2 HTTP headers. The tunnel and associated Work workspace must be owner-only, since all tunnel callers share the owner's local service identity. Shared workspace deployment requires an additional authenticated principal boundary.
Expand Down
45 changes: 39 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![CI](https://github.com/dk-code-factory/code-factory-plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/dk-code-factory/code-factory-plugin/actions/workflows/ci.yml)

Hosted checks and tag-driven package delivery are described in [CI and releases](docs/ci.md).
Hosted checks and package delivery are described in [CI and releases](docs/ci.md).

A single-user Linux service for GitHub issue/PR triage and interactive local Codex sessions. The React/TypeScript UI is embedded in the Go binary and runs inside ChatGPT Work through MCP Apps. Tailscale Funnel connects Work Cloud through an OAuth gateway; a private Tailscale Serve page limits connection approval to the owner. The OpenAI Secure MCP Tunnel adapter remains an alternative.

Expand All @@ -15,13 +15,13 @@ For local agent work, start with [AGENTS.md](AGENTS.md) and the
owner-approved Chrome control, private configuration, live tests,
recovery and remaining acceptance checks.

The portable private plugin is built with `make plugin` as `dist/code-factory-plugin-0.2.2.zip`. Browser Work uses the separate linked `code-factory-browser-plugin-0.2.2.zip`, described in [the plugin guide](docs/plugin.md). Install the linked browser package in your own account and retain its actual registered app mapping. Local marketplaces and MCP launch configuration are separate from that browser installation.
The portable private plugin is built with `make plugin` as `dist/code-factory-plugin-0.2.8.zip`. Browser Work uses the separate linked `code-factory-browser-plugin-0.2.8.zip`, described in [the plugin guide](docs/plugin.md). Install the linked browser package in your own account and retain its actual registered app mapping. Local marketplaces and MCP launch configuration are separate from that browser installation.

For the selected Tailscale route, follow [the Tailscale setup guide](docs/tailscale.md): install the release, run `code-factory configure-tailscale`, and add its HTTPS MCP URL to Work with OAuth. No Platform tunnel identifiers or runtime key are needed. Existing Tailscale services are preserved. The instructions below describing OpenAI tunnel credentials apply only to that alternative transport.

Install the release and its persistent private package at `~/.local/lib/code-factory/plugin` (the repository marketplace is `.agents/plugins/marketplace.json`) and invoke its `code-factory-setup` skill with Work local computer access. The skill performs installation, provider sign-in checks, tunnel configuration and connection verification. Repository, priority, profile, skill and Jira settings are managed inside the embedded UI.
Install the release and its persistent private package at `~/.local/lib/code-factory/plugin` (the repository marketplace is `.agents/plugins/marketplace.json`) and invoke its `code-factory-setup` skill with Work local computer access. The skill performs installation, provider sign-in checks, tunnel configuration and connection verification. Repository, priority, profile and skill settings are managed inside the embedded UI.

Onboarding requires Linux with a working user systemd session, an installed and authenticated Codex **0.161.0**, Git, existing GitHub CLI authentication, an OpenAI Secure MCP Tunnel with a restricted runtime key, owner-only access to its workspace/organization associations, and a Work host supporting MCP Apps and MCP Events. The setup skill opens a short-lived local password form for the runtime key. Jira has a separate password field in plugin settings.
Onboarding requires Linux with a working user systemd session, an installed and authenticated stable Codex **0.161.0 or later**, Git, existing GitHub CLI authentication, an OpenAI Secure MCP Tunnel with a restricted runtime key, owner-only access to its workspace/organization associations, and a Work host supporting MCP Apps and MCP Events. Later Codex versions require compatibility verification before managed activation. Pilot dependency updates use the owner fork at https://github.com/dkropachev/codex. The setup skill opens a short-lived local password form for the runtime key. Jira is disabled for this pilot; the embedded settings have no Jira credential form.

The tunnel is deliberately configured with a stdio command pointing at `code-factory mcp`; this proxy reads the local owner token and calls the authenticated loopback daemon. Cloud callers never receive the token. Everyone allowed to use that tunnel has the owner's application access: a shared workspace needs a separate authenticated identity boundary before use. Do not connect this single-user service to an unrestricted shared tunnel.

Expand Down Expand Up @@ -76,14 +76,44 @@ The CLI also supplies `install`, `configure-tunnel --id tunnel_…`, `onboarding
- The default inbox shows open issues and PRs. Initial imports form an unread baseline; subsequent discoveries get a New badge. New, unread and acted-on state are independent. Listing does not mark read. Detail views mark the exact revision displayed; an answer or action never suppresses later unread changes. GitHub website reading is not inferred.
- Priority resolves from override, then the most urgent mapped label, then a cached read-only Codex assessment. Assessment context includes local links, synchronized linked items and Jira context; policy or context changes invalidate inference. Failed assessments remain visible and retry later. Manual work takes precedence. Assessments disable discovered MCP servers/apps and never publish labels.
- Relationships preserve reference evidence. Manual links are separate records; adding or removing them changes neither GitHub nor Jira. Jira Cloud access uses only GET and configured `*.atlassian.net` tenants. Unavailable tickets display errors.
- Opening an item never starts work. Launching first creates a durable prepared snapshot of prompt, profile and selected skill bundles. The user reviews workspace, base, sandbox, approvals and publishing authority, then explicitly starts it. Start returns immediately while a dedicated Git worktree/branch and app-server process are created. Existing checkouts are preserved; managed clones reuse GitHub CLI authentication.
- Working tracks started issue/PR work through idle, interrupted and failed sessions until GitHub completion. Issues includes linked PR summaries; My PRs uses author identity and Review PRs uses individual/team requests. PR lifecycle, review approval and current-head CI stay independent. Explicit implementation links, including GitHub development links, can complete an issue on PR merge; incidental references cannot.
- Opening an item never starts work. Select a pipeline (one launch profile and one retained session). Launching first creates a durable prepared snapshot of prompt, profile and selected skill bundles. The user reviews workspace, base, sandbox, approvals and publishing authority, then explicitly starts it. Start returns immediately while a dedicated Git worktree/branch and app-server process are created. Existing checkouts are preserved; managed clones reuse GitHub CLI authentication.
- Local Codex authentication and repository instructions are reused. Profile publishing instructions are supplied to Codex; execution remains subject to Codex sandbox, approval and managed policies. An `ask` publishing setting is an agent instruction, not a separate GitHub authorization firewall. Do not grant broad network/MCP authority to a task whose external writes must be technically prohibited.
- Runs survive view/tunnel closure. Idle messages use `turn/start`; active messages use `turn/steer` with an expected turn ID. Questions and approvals become durable attention records, including original options, blocking state and request ID. Answers are durably claimed before delivery and never replayed automatically. Duplicate/stale answers fail. Interrupt, explicit resume and worktree cleanup are separate actions. Cleanup refuses uncommitted changes.
- Native RPC and structured agent-message questions appear in Messages, including nonblocking questions. For a stopped textual ask, an isolated helper can request a native form in at most two question-only Plan turns, then expose free-text continuation and the same-session console. Recovery state and attempt counts persist; mode restoration is explicit and uncertain sends are never replayed.
- App-server or daemon loss invalidates live request IDs and marks runs interrupted. Resume reconnects stored Codex history in the retained worktree; it does not replay the initial task. Prepared runs remain explicit launch candidates. History and snapshots stay local after worktree cleanup.
- UI polling uses app-only MCP tools once per second while visible, with hidden/disconnected backoff. Transcript and diff data are journaled in bounded chunks and paged. MCP Events sends state changes and attention alerts, never output tokens. Callback verification, Standard Webhooks HMAC, expiring durable subscriptions, bounded retries, key rotation and stable delivery IDs are implemented. Callback connections validate public addresses and prohibit redirects. Events use `cursor: null` (no protocol replay); local journal history remains available.
- UI polling uses app-only MCP tools once per second while visible, with hidden/disconnected backoff. Transcript and diff data are journaled in bounded chunks and paged. MCP Events sends state changes and attention alerts, never output tokens. The optional session console uses that same bounded local journal and session controls. Callback verification, Standard Webhooks HMAC, expiring durable subscriptions, bounded retries, key rotation and stable delivery IDs are implemented. Callback connections validate public addresses and prohibit redirects. Events use `cursor: null` (no protocol replay); local journal history remains available.

State lives under `$XDG_DATA_HOME/code-factory` or `~/.local/share/code-factory`: SQLite WAL state/events, encrypted credentials, a mode-0600 encryption key and owner token, managed clones, retained worktrees, and immutable launch skill snapshots. Keep this directory private. Losing the encryption key loses stored credentials. Service credentials and secret question answers are redacted from incoming Codex output; answer bodies are not journaled. As with any local coding agent, same-user filesystem access is a trust boundary, not protection against a compromised local account.

## GitHub read boundary

The application depends on `providers.GitHubSource`. The daemon supplies
`CachedGitHub` around the HTTP adapter, using the same read methods for identity,
teams, repository indexes, item details, lifecycle checks, review requests,
notifications and posted reviews. Local usage accounting stays live local state.

Normal queries return an unexpired cached result. Cache misses, expiry and
explicit invalidation fetch through the existing budgeted adapter and retain
successful results. Cache entries are isolated by API endpoint and authenticated
principal, persist in private state, and are bounded to 64 MiB and 4,096 entries.
Cached results preserve their provider observation times and decode into
independent values. Errors and partial enrichment failures do not become
successful cache entries.

Use `providers.WithGitHubRead(ctx, providers.RequireLive)` when a current remote
check is required. This bypasses both query and REST/GraphQL TTLs, allows
conditional HTTP validation, and writes the response back to the shared cache.
Initial/resumed execution, new review-notification targets, post-turn receipt
verification and explicit repository polling use that mode. A failed live check
returns an error; it does not silently return an older success. Ordinary saved
tracking/UI reads still return immediately and refresh external observations in
the background. `CachedGitHub.Invalidate(ctx, resource)` expires the current
principal's item/repository queries, including affected repository indexes;
an empty resource expires that principal's query cache. Other repositories and
principals are preserved. Cache hits need no GitHub HTTP request and remain
available while another query waits on the network.

## Layout

| Directory | Responsibility |
Expand All @@ -107,3 +137,6 @@ Suspected Code Factory defects can be submitted through the bundled
`code-factory-report-issue` skill and followed in **Reported issues**. The private
ledger, automatic investigation/filing prerequisites, recovery and verified
release tracking are described in [issue reporting](docs/reporting.md).
The [private dependency administration API](docs/dependency-admin.md) checks and
updates Codex, installed plugins and GitHub-installed skills through identified,
recoverable owner operations.
Loading