OpenProgram · Engineering design

Repository structure

This page defines a core-first monorepo: the root openprogram/ is the Agent core; Server, Web, Desktop, and CLI are runnable applications consuming it, all under apps/. Directories should express runtime boundaries and dependency direction while preserving product behavior and user-data compatibility.

Status
Approved target · migration in progress
Audience
Maintainers and reviewers
Scope
Core, applications, build and release layout
Excluded
Product behavior and public API changes

1. Design principles

Separate core and applications

openprogram/ contains only core capabilities such as Agent, Context, Session, Provider, Program, Tool, Memory, and Runtime. All runnable entry points reside in apps/. Core business domains must not depend on applications. Compatibility adapters retained within the core import package for old public entry points may delegate one-way to application packages, but must not contain application implementations.

Split along verifiable boundaries

Move code only when it has independent inputs, outputs, and test entry points. Introducing a mixin, manager, or facade solely because a file is long is not a valid decomposition.

Keep public interfaces stable

Preserve existing CLI commands, HTTP/WS protocols, ports, user-data directories, and necessary Python import compatibility during migration. Move, verify, and commit each application independently.

Separate current design from implementation records

This HTML describes the long-term structure. Adjacent implementation notes maintain code locations, compatibility boundaries, verification methods, and unfinished work. Use Git for historical commits and review records.

2. Top-level responsibilities

OpenProgram/
  apps/
    server/      FastAPI, HTTP, WebSocket, authentication, and static hosting
    web/         Next.js Web application
    desktop/     Electron desktop application
    cli/         Python CLI and Ink TUI application
  openprogram/   OpenProgram Agent core and Python SDK
  tests/         Python tests: layer / product domain
  docs/          User documentation and design records
  scripts/       Executable or importable development, validation, and release tools
  references/    Reference implementation snapshots and local comparison material
  website/       Official website source
  pyproject.toml Single Python aggregate-project configuration
  uv.lock        Sole Python lockfile
  package.json   npm workspace entry
  package-lock.json Sole npm workspace lockfile

.github/, .codegraph/ and .superpowers/ are repository infrastructure, not product runtime directories. The root retains only the two ecosystems’ entry files and lockfiles, project metadata, and entry documentation. Root pyproject.toml continues to define the single user-installable openprogram aggregate distribution, with the sole uv.lock managing the Python development environment. G2 does not create a memberless [tool.uv.workspace] or split Core, Server, and CLI into three public distributions. Root package.json declares npm workspaces for Web, Desktop, and Ink CLI, sharing the sole package-lock.json. These are source and build configuration files, not files in ordinary user installations.

Web pins React 18; Ink CLI pins React 19. npm’s default hoisting can make shared React peer and type dependencies affect another application. The private root package therefore declares exact React 18, react-reconciler 0.29, and type versions as dependency-layout constraints. CLI’s React 19 and react-reconciler 0.33 remain in its own workspace. CLI does not depend on third-party hook packages resolving React from the root. This constraint adds no product runtime behavior and does not unify the applications’ React major versions.

The core Python import package resides at the root openprogram/. It is the Agent Core / SDK shared by Server, CLI, and Harness, not an ordinary application. Since there is no second shared Python package, do not create packages/. Source ownership and release distribution are separate boundaries: retain one user-installable openprogram wheel that still includes openprogram, openprogram_server and openprogram_cli. Application-specific scripts live in apps/<name>/scripts/, cross-application development and verification commands in scripts/, and official runtime, installer, and release commands in scripts/release/.

The existing public URL continues to provide scripts/install-release.sh. This file handles compatibility distribution only: a complete checkout executes scripts/release/install-release.sh; when downloaded alone, it retrieves the official implementation from the same verified repository and immutable tag into a temporary file, then executes it.scripts/install.sh, scripts/install.ps1, scripts/refresh-local-app.sh and scripts/promote_stable.sh retain their paths; local refresh continues to reuse staging and version-verification helpers under scripts/release/.

The current checkout has completed release-script and Node-workspace organization: official release scripts are under scripts/release/; Web, Desktop, and Ink CLI are managed by root npm workspaces and share the sole package-lock.json; Python Core remains at root openprogram/. Root pyproject.toml continues to publish a single distribution containing Core, Server, and Python CLI: openprogram wheel.

OpenProgram does not distribute default skills with its installation; Programs provides built-in product workflows.openprogram/skills/ only implements AgentSkills-compatible loading from remote caches, plugins, the user directory ~/.openprogram/skills/, and the current project <cwd>/skills/. The repository does not create skills_bundled/ or a second hidden copy.

tests/ Python cases use tests/<layer>/<product-domain>/test_*.py, selecting a layer based on the strongest actual dependency. Detailed boundaries are maintained by Testing system and repository contracts.

Core and application packages

openprogram/ top-level directories contain only independently explainable core product domains or stable protocol boundaries, such as agent/, programs/, context/, memory/ and providers/. Sub-capabilities belong within their product domains. Context’s Git DAG resides in context/git/, no longer occupying a separate top-level contextgit/ directory. FastAPI routes, WebSocket handlers, static frontend hosting, Electron, and UI code are not part of the core package.

apps/server/openprogram_server/ is the Python server application; its FastAPI routes, WebSocket actions, owner authentication, static hosting, and server-only helpers reside in _webui/. During compatibility, these files still load under the existing openprogram.webui.* names. The root package only locates the same application source without duplicating module state.apps/cli/ is the CLI application workspace. Ink TUI uses its src/, tests/ and package.json; the Python parser, dispatcher, Rich fallback, and setup flow reside in apps/cli/python/openprogram_cli/.openprogram.cli retain only compatibility loaders and module entries; neither compatibility boundary contains new application implementations.

Tool configuration, favorites, and other profile state are user data written to ~/.openprogram[-profile]/, not source or wheel seeds stored in openprogram/. Compatibility reads check only the legacy openprogram/webui/ package location and copy once into profile state. They must not depend on Server module paths migrated to apps/server.

The repository currently does not create packages/. Reconsider this directory only when a second shared package has an independent stable public entry and is consumed by at least two applications. Do not create empty packages for hypothetical protocol, UI, or configuration reuse.

__pycache__/, .DS_Store, build artifacts, and Finder conflict copies are not repository structure. They remain Git-ignored and may be cleaned, but are not code-layering or acceptance evidence. User-installed programs/packages/ checkouts are local product data and must not be removed during source reorganization.

3. Handling oversized files

FileCurrent stateDecisionBoundary
openprogram/cli/ Retain only the compatibility loader, python -m openprogram.cli entry, and boundary documentation Migrated Application implementation resides in apps/cli/python/openprogram_cli/; source development retains compatibility through editable installation or uv run, preserving python -m openprogram and python -m openprogram.cli; wheels additionally retain canonical python -m openprogram_cli and the console script.
apps/desktop/main.js Windows, updates, WebViews, tab transfers, and menus coexist in nearly 4,000 lines Implement in batches Pure menu geometry has been extracted to menu-geometry.js, pure worker-recovery state to worker-recovery-state.js, and transfer-payload validation to tab-transfer-validation.js. Move HTTP probing, process/window lifecycles, native WebView ownership changes, tab-transfer coordination, and menu hosting only after each has execution-level acceptance.
apps/web/lib/desktop/desktop-bridge.ts Types, view state, and tab transfers coexist in nearly 2,000 lines Implement in batches Public WebTab and Desktop-service types have been extracted to desktop-bridge-types.ts, preload-facing transfer contracts to desktop-transfer-types.ts, and re-exported from the original file. Aggregate bridge, view state, journal persistence, and tab-transfer coordination remain until independently executable verification boundaries are identified.
runtime.py, runner.py, resource_governance.py Long file with concentrated core state-machine logic and invariants Do not split by length Split only for independently verifiable responsibilities or duplicate implementations; introduce no mixin layer.
Large Web / Desktop check scripts Some scripts combine fixtures, scenario execution, and multiple structural assertions; the longest exceed 3,000 lines Later batches Extract shared fixtures and independently executable scenarios first. Retain original command entry points; introduce no test framework merely to shorten files.

4. Documentation information architecture

User documentation

start/, install/, capabilities/, interfaces/, models/, integrations/, server/, reference/. Included in public navigation and search.

Current design

reference/design/. Present currently effective designs by product domain. Group UI documents into foundations, conversation editing, browser tabs, settings/catalog, and workspace.

Implementation records

Implementation notes adjacent to design pages and reference/design/plans/ describe current implementation boundaries, verification requirements, and remaining work. Maintain implementation status together at the end; do not duplicate design bodies or accumulate historical commit/review logs.

Internal plans

docs/superpowers/ remain in Git for maintainer reference and are excluded from the public site. Those still referenced by current designs under reference/design/plans/ remain published in a separate Plans group.

Root README.md explains the complete product; openprogram/README.md explains the core SDK; apps/server/README.md, apps/web/README.md, apps/desktop/README.md and apps/cli/README.md explain each runnable entry. Entry READMEs describe only current responsibilities, dependency directions, and verification commands.

5. Adopted and rejected choices

ChoiceConclusionReason
Root openprogram/ core + apps/ runnable entriesAdoptedThe core remains a top-level project entry, while Server, Web, Desktop, and CLI application boundaries are visible under apps/.
Move-only application migrationAdoptedMove paths and repair builds, imports, and scripts first, then separately split large internal files to avoid concurrent behavior changes.
Organize documents through navigation groupsAdoptedAvoid breaking old links through bulk file moves.
Rename openprogram/ to backendRejectedOpenProgram is the Agent core and SDK; Server is just one application entry.
Keep Server implementation in openprogram/webui/RejectedThat directory mixes server code, old static UI, build artifacts, and Web naming, obscuring actual responsibilities.
Automatically split files by a fixed line countRejectedLine count does not establish independent responsibilities and tends to produce forwarding-only modules.
Introduce a dependency-injection framework for decompositionRejectedExisting module functions and explicit parameters suffice to preserve boundaries.
Move all applications in one commitRejectedMigrate and verify applications separately. Their final state belongs under apps/, but not through one unreviewable commit.

6. Acceptance contract

See implementation status and reproducible commands in Repository structure implementation.