How to Contribute to the holaOS Project: A Complete Developer Guide
Contributing to holaOS requires setting up a Node 24.14.1 environment, choosing between Desktop (Electron), Runtime (Fastify API), or Harness (agent adapter) tracks, and running targeted validation scripts before submitting PRs with Conventional Commits.
holaOS is a monorepo housing three distinct subsystems that power an AI-native operating environment. Whether you are fixing UI bugs in the desktop shell, extending the HTTP API, or bridging agent actions to system calls, understanding the repository structure and validation workflows ensures your contributions merge smoothly.
Understanding the holaOS Monorepo Architecture
Before writing code, identify which subsystem your change affects. The repository is organized into three primary domains, each with strict contracts between them.
| Subsystem | Core Code Location | Typical Entry Points | Validation Commands |
|---|---|---|---|
| Desktop shell (Electron UI, preload bridge, main process) | apps/desktop/ |
apps/desktop/electron/main.ts, apps/desktop/src/** |
npm run desktop:typecheck + npm run desktop:e2e |
| Runtime HTTP API (Fastify server, workers, state‑store) | runtime/api-server/, runtime/state-store/ |
runtime/api-server/src/app.ts, runtime/state-store/src/store.ts |
npm run runtime:api-server:typecheck + npm run runtime:test |
| Agent harness (adapter, run projection) | runtime/harness-host/, runtime/harnesses/ |
runtime/harness-host/src/**, runtime/harnesses/src/** |
npm run runtime:harness-host:test + npm run runtime:api-server:test |
The Desktop runs on Electron and maintains strict IPC contracts between the main process and renderer. The Runtime exposes HTTP endpoints that agents consume, backed by a SQLite state store. The Harness translates agent intentions into runtime requests via adapter contracts.
Setting Up Your Development Environment
Start with the automated installer or manual steps documented in INSTALL.md. You will need Git and Node.js version 24.14.1 installed globally.
Run the one-line installer from the repository root:
./scripts/install.sh
If installing manually, execute these steps in order:
- Clone the repository and navigate to the root.
- Run
npm run desktop:installto bootstrap dependencies. - Copy the environment template file to
.envand configure local variables. - Prepare the local runtime bundle for testing.
Choosing Your Contribution Track
Select the track that matches the scope of your change. Each track has distinct entry points and validation requirements.
Desktop Track (Electron)
Work in this track when modifying UI components, window management, or inter-process communication (IPC) logic. Key files include apps/desktop/electron/main.ts for the main process and apps/desktop/electron/preload.ts for the preload bridge.
When adding or modifying IPC channels, you must update both the preload exposure and the main process handler.
Runtime Track (Fastify API)
Work here when adding HTTP endpoints, modifying business logic, or changing the SQLite-backed state persistence. Primary files are runtime/api-server/src/app.ts for route registration and runtime/state-store/src/store.ts for session and artifact storage.
Harness Track (Agent Integration)
Work here when adapting agent outputs to system actions or modifying the projection layer. Core files live in runtime/harness-host/src/adapter.ts and runtime/harnesses/src/**, defining how agent requests map to runtime commands.
The Contribution Workflow
Follow this seven-step workflow to ensure your PR passes CI and review.
-
Identify the subsystem using the table above to determine which validation scripts to run later.
-
Make atomic changes scoped to a single concern. Edit source files within the appropriate directory (e.g.,
apps/desktop/src/for UI components orruntime/api-server/src/for routes). -
Update contracts and types whenever you touch IPC channels, HTTP routes, or harness adapters. This includes TypeScript definitions in
preload.ts, Fastify schemas inapp.ts, or interface definitions inadapter.ts. -
Run narrow validation to catch type errors and regressions early:
- For Desktop changes:
npm run desktop:typecheck - For Runtime changes:
npm run runtime:test - For Harness changes:
npm run runtime:harness-host:test
- For Desktop changes:
-
Run broad validation for mixed changes:
npm run desktop:typecheck npm run runtime:test npm run docs:typecheck npm run docs:build -
Commit with Conventional Commits using prefixes like
feat:,fix:,docs:, orchore:. Include a bulleted body explaining what changed and why. Keep commits focused on one cohesive change. -
Open a Pull Request describing user-visible impact, migration steps, new environment variables, and the validation commands you executed. Reviewers expect narrow scope, updated tests, and documentation.
Code Examples for Common Contributions
Adding a New Electron IPC Channel
When exposing new functionality from the main process to the renderer, update both the preload script and the main handler.
In apps/desktop/electron/preload.ts, expose the API:
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("myFeature", {
getStatus: () => ipcRenderer.invoke("my-feature:get-status"),
});
In apps/desktop/electron/main.ts, register the handler:
ipcMain.handle("my-feature:get-status", async () => {
// Implementation logic here
return { ok: true, message: "All good" };
});
Validate your changes:
npm run desktop:typecheck
npm run desktop:e2e
Adding a New Fastify Route
Extend the HTTP API by registering new routes in runtime/api-server/src/app.ts.
import { FastifyInstance } from "fastify";
export async function registerMyRoute(app: FastifyInstance) {
app.get("/api/v1/my-endpoint", async (req, reply) => {
return { hello: "world" };
});
}
Import and register the route in the server builder:
import { registerMyRoute } from "./my-endpoint";
export async function buildServer() {
const app = fastify();
await registerMyRoute(app);
return app;
}
Run validation:
npm run runtime:api-server:typecheck
npm run runtime:test
Extending the Harness Adapter
Modify runtime/harness-host/src/adapter.ts to handle new agent request types:
export interface MyFeatureRequest {
type: "my-feature";
payload: { foo: string };
}
export async function handleMyFeature(req: MyFeatureRequest, ctx: HarnessContext) {
return { result: `Processed ${req.payload.foo}` };
}
Register the handler in runtime/harness-host/src/dispatcher.ts:
import { handleMyFeature } from "./adapter";
dispatchMap.set("my-feature", handleMyFeature);
Validate with harness-specific tests:
npm run runtime:harness-host:test
npm run runtime:test
Key Files Every Contributor Should Know
| File | Subsystem | Purpose |
|---|---|---|
apps/desktop/electron/main.ts |
Desktop | Main process entry; defines IPC handlers and window management |
apps/desktop/electron/preload.ts |
Desktop | Preload bridge exposing Node APIs to renderer |
runtime/api-server/src/app.ts |
Runtime | Fastify route registration and server bootstrap |
runtime/state-store/src/store.ts |
Runtime | SQLite-backed persistence for sessions and artifacts |
runtime/harness-host/src/adapter.ts |
Harness | Agent action-to-runtime translation layer |
runtime/harness-host/src/dispatcher.ts |
Harness | Handler routing map for harness requests |
apps/docs/content/docs/contribute/index.mdx |
Docs | Contribution guidelines and track selection |
scripts/install.sh |
Setup | One-line development environment installer |
Summary
- holaOS is organized into three subsystems: Desktop (Electron), Runtime (Fastify/SQLite), and Harness (agent adapters).
- Use the narrowest validation script for your change (e.g.,
npm run desktop:typecheckfor UI work) to maintain fast feedback loops. - Always update type contracts when modifying IPC channels, HTTP routes, or harness adapters.
- Follow Conventional Commits with descriptive bodies and keep PRs narrowly scoped to simplify review.
Frequently Asked Questions
What Node.js version is required to contribute to holaOS?
You must use Node.js 24.14.1 as specified in INSTALL.md. The project relies on specific Node APIs and npm behaviors present in this version, and CI pipelines enforce this constraint strictly.
How do I know which validation scripts to run before submitting a PR?
Match your changed files to the subsystem table in the contribution docs. If you modified files under apps/desktop/, run npm run desktop:typecheck and npm run desktop:e2e if IPC logic changed. For runtime/api-server/ changes, run npm run runtime:api-server:typecheck and npm run runtime:test. Mixed changes require running all relevant suites.
Why do I need to update both preload.ts and main.ts when adding a desktop feature?
The Electron security model requires explicit context bridging between the Node.js main process and the Chromium renderer. The preload.ts script exposes a controlled API surface to the frontend, while main.ts implements the actual handler logic. Updating only one side breaks the IPC contract and causes runtime errors.
Where is the best place to start if I want to add new HTTP endpoints for agents?
Add your route definitions in runtime/api-server/src/app.ts and implement business logic in a new file under the same directory. Import and register your route in the buildServer() function. Ensure you run npm run runtime:api-server:typecheck to validate TypeScript definitions before submitting.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →