docs: add human-friendly documentation
Some checks failed
Security Scan / security (push) Failing after 17s
Test / test (push) Failing after 39s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-03-11 13:02:40 +00:00
parent d0c057d20c
commit e2c6a79487
3 changed files with 650 additions and 0 deletions

259
docs/architecture.md Normal file
View file

@ -0,0 +1,259 @@
---
title: Architecture
description: Internal architecture of Core IDE -- Go backend, Angular frontend, MCP bridge, headless job runner, and data flow between components.
---
# Architecture
Core IDE is a single binary that operates in two distinct modes, selected at startup.
## Mode selection
In `main.go`, the entry point inspects the command-line arguments and the display environment:
```go
if headless || !hasDisplay() {
startHeadless()
return
}
```
`hasDisplay()` returns `true` on Windows unconditionally, and on Linux/macOS only when `DISPLAY` or `WAYLAND_DISPLAY` is set. This means the binary automatically falls back to headless mode on servers.
## GUI mode
### Wails application
The GUI is a Wails 3 application. The Angular frontend is embedded into the binary at compile time via `//go:embed`:
```go
//go:embed all:frontend/dist/wails-angular-template/browser
var assets embed.FS
```
Two Wails services are registered:
- `GreetService` -- a minimal service demonstrating Wails method bindings.
- `MCPBridge` -- the main service that wires up the MCP HTTP server, WebSocket hub, and webview automation.
### System tray
The application runs as a macOS "accessory" (no Dock icon) with a system tray icon. Clicking the tray icon reveals a 380x480 frameless window at `/tray` that shows quick stats, recent projects, and action buttons.
On macOS, a template icon (`icons/apptray.png`) is used so it adapts to light/dark mode automatically. On other platforms, the same icon is set as both light and dark variants.
### Angular frontend
The frontend is an Angular 20+ application using standalone components (no NgModules). It has two routes:
| Route | Component | Purpose |
|-------|-----------|---------|
| `/tray` | `TrayComponent` | Compact system tray panel -- status, quick actions, recent projects |
| `/ide` | `IdeComponent` | Full IDE layout with sidebar navigation |
The root route (`/`) redirects to `/tray` because the tray panel is the default window.
#### Wails runtime bridge
Components communicate with the Go backend through the `@wailsio/runtime` package:
- **Events.On** -- subscribes to events emitted by Go (e.g. `time` events for the clock display).
- **Events.Emit** -- sends events to Go (e.g. `action` events for quick actions like `new-project`, `run-dev`).
- **Generated bindings** -- `frontend/bindings/` contains auto-generated TypeScript functions that call Go methods by ID (e.g. `GreetService.Greet`).
The `IdeComponent` lazily imports `@wailsio/runtime` to avoid SSR issues:
```typescript
import('@wailsio/runtime').then(({ Events }) => {
this.timeEventCleanup = Events.On('time', (time: { data: string }) => {
this.currentTime.set(time.data);
});
});
```
### MCPBridge
`MCPBridge` is the central orchestrator in GUI mode. It is registered as a Wails service and receives the `ServiceStartup` lifecycle callback once the application initialises.
#### Initialisation sequence
1. Obtain the Wails `application.App` reference.
2. Wire the `webview.Service` with the app so it can access windows.
3. Set up a console message listener on all windows.
4. Inject console capture JavaScript into existing windows (with a polling delay to wait for window creation).
5. Start the HTTP server on `127.0.0.1:9877`.
#### HTTP endpoints (GUI mode)
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Returns `{"status":"ok","mcp":true,"webview":true}` |
| `/mcp` | GET | Server metadata (name, version, capabilities, WebSocket URL) |
| `/mcp/tools` | GET | Lists all 27 available webview tools |
| `/mcp/call` | POST | Executes a tool -- accepts `{"tool":"...","params":{...}}` |
| `/ws` | GET | WebSocket endpoint for GUI clients |
#### Webview tools
The MCP bridge exposes 27 tools for programmatic interaction with the application's webview windows. These are grouped by function:
**Window management:**
- `webview_list` -- enumerate all windows (name, title, URL)
**JavaScript execution:**
- `webview_eval` -- execute arbitrary JavaScript in a named window
**Console and errors:**
- `webview_console` -- retrieve captured console messages (filterable by level)
- `webview_console_clear` -- clear the console buffer
- `webview_errors` -- retrieve captured error messages
**DOM interaction:**
- `webview_click` -- click an element by CSS selector
- `webview_type` -- type text into an element
- `webview_query` -- query DOM elements by selector
- `webview_hover` -- hover over an element
- `webview_select` -- select an option in a dropdown
- `webview_check` -- check/uncheck a checkbox or radio button
- `webview_scroll` -- scroll to an element or position
**DOM inspection:**
- `webview_element_info` -- get detailed information about an element
- `webview_computed_style` -- get computed CSS styles for an element
- `webview_highlight` -- visually highlight an element with a coloured overlay
- `webview_dom_tree` -- get the DOM tree structure (configurable depth)
**Navigation:**
- `webview_navigate` -- navigate to a URL (http/https only)
- `webview_url` -- get the current page URL
- `webview_title` -- get the current page title
- `webview_source` -- get the full page HTML source
**Capture:**
- `webview_screenshot` -- capture the full page as a base64 PNG
- `webview_screenshot_element` -- capture a specific element as a base64 PNG
- `webview_pdf` -- export the page as a PDF (base64 data URI)
- `webview_print` -- open the native print dialogue
**Performance and network:**
- `webview_performance` -- get performance timing metrics
- `webview_resources` -- list loaded resources (scripts, stylesheets, images)
- `webview_network` -- get logged network requests
- `webview_network_clear` -- clear the network request log
- `webview_network_inject` -- inject a network interceptor for detailed logging
All tools accept parameters as JSON. Most require a `window` parameter (the window name, e.g. `"tray-panel"`) and a `selector` parameter (a CSS selector).
### ClaudeBridge
The `ClaudeBridge` is a WebSocket relay designed to forward messages between GUI WebSocket clients and an upstream MCP core server at `ws://localhost:9876/ws`. It maintains:
- A persistent connection to the upstream server with automatic reconnection (5-second backoff).
- A set of client connections (GUI browsers connecting via `/ws`).
- A broadcast channel that fans out messages from the upstream server to all connected clients.
- Message filtering -- only `claude_message` type messages from clients are forwarded upstream.
The Claude bridge is currently disabled in the code (`b.claudeBridge.Start()` is commented out) because port 9876 does not host an MCP WebSocket server at present.
## Headless mode
### Overview
Headless mode turns the binary into a CI/CD daemon. It polls Forgejo repositories for actionable events and dispatches work to AI agents.
### Components
```
startHeadless()
|
+-- Journal (filesystem, ~/.core/journal/)
|
+-- Forge client (Forgejo API)
|
+-- Forgejo source (repo list from CORE_REPOS env or defaults)
|
+-- Job handlers (ordered, first-match-wins):
| 1. PublishDraftHandler
| 2. SendFixCommandHandler
| 3. DismissReviewsHandler
| 4. EnableAutoMergeHandler
| 5. TickParentHandler
| 6. DispatchHandler (agent dispatch via Clotho spinner)
|
+-- Poller (60-second interval)
|
+-- Daemon (PID file at ~/.core/core-ide.pid, health at 127.0.0.1:9878)
|
+-- Headless MCP server (127.0.0.1:9877)
```
### Job handler pipeline
The poller queries the Forgejo source for jobs, then passes each job through the handler list. The first handler that matches claims the job. The handlers are ordered so that lightweight operations (publishing drafts, dismissing stale reviews) run before the heavy-weight agent dispatch.
The `DispatchHandler` uses the Clotho spinner to allocate work to configured AI agents. Agent targets and the Clotho configuration are loaded from the Core config system.
### Journal
The journal persists job state to `~/.core/journal/` on the filesystem. This prevents the same job from being processed twice across daemon restarts.
### HTTP endpoints (headless mode)
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Returns `{"status":"ok","mode":"headless","cycle":<n>}` |
| `/mcp` | GET | Server metadata with `"mode":"headless"` |
| `/mcp/tools` | GET | Lists 3 tools: `job_status`, `job_set_dry_run`, `job_run_once` |
| `/mcp/call` | POST | Executes a headless tool |
### Headless tools
| Tool | Description |
|------|-------------|
| `job_status` | Returns current poll cycle count and dry-run state |
| `job_set_dry_run` | Enable or disable dry-run mode at runtime (`{"enabled": true}`) |
| `job_run_once` | Trigger a single poll-dispatch cycle immediately |
### Health check
The daemon exposes a separate health endpoint on port 9878 via the `go-process` package. This is distinct from the MCP health on port 9877 and is intended for process supervisors (systemd, launchd).
## Port summary
| Port | Service | Mode |
|------|---------|------|
| 9877 | MCP HTTP server (tools, WebSocket) | Both |
| 9878 | Daemon health check | Headless only |
| 9876 | Upstream MCP core (external, not started by this binary) | N/A |
## Data flow diagrams
### GUI mode
```
System Tray Click
--> Tray Panel Window (/tray)
--> Angular TrayComponent
--> Events.Emit('action', ...)
--> Go event handler
MCP Client (e.g. Claude Code)
--> POST /mcp/call {"tool":"webview_eval","params":{"window":"tray-panel","code":"..."}}
--> MCPBridge.handleMCPCall()
--> MCPBridge.executeWebviewTool()
--> webview.Service.ExecJS()
--> Wails webview
```
### Headless mode
```
Poller (every 60s)
--> Forgejo Source (API query)
--> Job list
--> Handler pipeline
--> PublishDraft / SendFix / DismissReviews / ...
--> DispatchHandler
--> Clotho Spinner
--> Agent target
```

294
docs/development.md Normal file
View file

@ -0,0 +1,294 @@
---
title: Development
description: How to build, test, and contribute to Core IDE.
---
# Development
## Prerequisites
| Tool | Version | Purpose |
|------|---------|---------|
| Go | 1.26+ | Backend compilation |
| Node.js | 22+ | Angular frontend build |
| npm | (bundled with Node) | Frontend dependency management |
| Wails 3 CLI | alpha.64+ | Desktop application framework (`wails3`) |
| `core` CLI | latest | Build system (`core build`) |
The module lives inside a Go workspace (`~/Code/go.work`) and depends on three sibling modules via `replace` directives in `go.mod`:
```
replace (
forge.lthn.ai/core/go => ../go
forge.lthn.ai/core/go-process => ../go-process
forge.lthn.ai/core/gui => ../gui
)
```
Ensure these directories exist alongside the `ide/` directory before building.
## Building
### Development mode (hot-reload)
```bash
wails3 dev
```
This starts the Angular dev server, watches Go files for changes, rebuilds, and re-launches the application automatically. The Wails dev mode configuration is in `build/config.yml` under the `dev_mode` key.
### Production build
Using the Core CLI (preferred):
```bash
core build
```
This reads `.core/build.yaml` and produces a platform-native binary. The build configuration enables CGO (required by Wails), strips debug symbols (`-s -w`), and uses `-trimpath`.
Using Wails directly:
```bash
wails3 build
```
### Cross-compilation targets
The `.core/build.yaml` defines three targets:
| OS | Architecture |
|----|-------------|
| darwin | arm64 |
| linux | amd64 |
| windows | amd64 |
### Frontend-only build
To build or serve the Angular frontend independently (useful for UI-only development):
```bash
cd frontend
npm install
npm run dev # Development server with hot-reload
npm run build # Production build to frontend/dist/
npm run test # Run Jasmine/Karma tests
```
## Testing
### Go tests
```bash
core go test # Run all tests
core go test --run TestName # Run a specific test
core go cov # Generate coverage report
core go cov --open # Open coverage HTML in browser
```
### Frontend tests
```bash
cd frontend
npm run test
```
This runs the Angular test suite via Karma with Chrome.
### Quality assurance
```bash
core go qa # Format + vet + lint + test
core go qa full # + race detector, vulnerability scan, security audit
```
### CI pipelines
Two Forgejo workflows are configured in `.forgejo/workflows/`:
| Workflow | Trigger | Description |
|----------|---------|-------------|
| `test.yml` | Push to `main`/`dev`, PRs to `main` | Runs Go tests with race detection and coverage |
| `security-scan.yml` | Push to `main`/`dev`/`feat/*`, PRs to `main` | Runs security scanning |
Both workflows are reusable, imported from `core/go-devops`.
## Project structure
```
ide/
main.go # Entry point
mcp_bridge.go # MCPBridge Wails service (GUI mode)
claude_bridge.go # WebSocket relay to upstream MCP
headless.go # Headless daemon (job runner)
headless_mcp.go # Headless MCP HTTP server
greetservice.go # Sample Wails service
icons/
icons.go # Embedded icon assets
apptray.png # System tray icon
systray-mac-template.png
systray-default.png
frontend/
src/
app/
app.ts # Root component (router outlet)
app.routes.ts # Route definitions (/tray, /ide)
app.config.ts # Angular providers
pages/
tray/ # System tray panel component
ide/ # Full IDE layout component
components/
sidebar/ # Navigation sidebar component
bindings/ # Auto-generated Go method bindings
package.json # npm dependencies
angular.json # Angular CLI configuration
build/
config.yml # Wails 3 project configuration
appicon.png # Application icon
darwin/ # macOS-specific (Info.plist, .icns)
linux/ # Linux-specific (systemd, AppImage, nfpm)
windows/ # Windows-specific (NSIS, MSIX, manifest)
.core/
build.yaml # core build configuration
.forgejo/
workflows/ # CI pipeline definitions
go.mod
go.sum
```
## Adding a new Wails service
1. Create a new Go file with a struct and methods you want to expose to the frontend:
```go
// myservice.go
package main
type MyService struct{}
func (s *MyService) DoSomething(input string) (string, error) {
return "result: " + input, nil
}
```
2. Register the service in `main.go`:
```go
Services: []application.Service{
application.NewService(&GreetService{}),
application.NewService(mcpBridge),
application.NewService(&MyService{}), // add here
},
```
3. Run `wails3 dev` or `wails3 build` to regenerate TypeScript bindings in `frontend/bindings/`.
4. Import and call the generated function from Angular:
```typescript
import { DoSomething } from '../bindings/changeme/myservice';
const result = await DoSomething('hello');
```
## Adding a new MCP tool
To add a new webview tool to the MCP bridge:
1. Add the tool metadata to the `handleMCPTools` method in `mcp_bridge.go`:
```go
{"name": "webview_my_tool", "description": "What it does"},
```
2. Add a case to the `executeWebviewTool` switch in `mcp_bridge.go`:
```go
case "webview_my_tool":
windowName := getStringParam(params, "window")
// Call webview.Service methods...
result, err := b.webview.SomeMethod(windowName)
if err != nil {
return map[string]any{"error": err.Error()}
}
return map[string]any{"result": result}
```
3. The tool is immediately available via `POST /mcp/call`.
## Adding a new Angular page
1. Create a new component:
```bash
cd frontend
npx ng generate component pages/my-page --standalone
```
2. Add a route in `frontend/src/app/app.routes.ts`:
```typescript
import { MyPageComponent } from './pages/my-page/my-page.component';
export const routes: Routes = [
{ path: 'my-page', component: MyPageComponent },
// ... existing routes
];
```
3. If the page needs to communicate with Go, use the Wails runtime:
```typescript
import { Events } from '@wailsio/runtime';
// Listen for Go events
Events.On('my-event', (data) => { ... });
// Send events to Go
Events.Emit('my-action', payload);
```
## Platform-specific notes
### macOS
- The application runs as an "accessory" (`ActivationPolicyAccessory`), meaning it has no Dock icon and only appears in the system tray.
- Bundle identifier: `com.lethean.core-ide`
- Minimum macOS version: 10.15 (Catalina)
- The `Info.plist` is at `build/darwin/Info.plist`.
### Linux
- A systemd service file is provided at `build/linux/core-ide.service` for running in headless mode.
- A user-scoped service file is also available at `build/linux/core-ide.user.service`.
- nfpm packaging configuration is at `build/linux/nfpm/nfpm.yaml`.
- AppImage build script is at `build/linux/appimage/build.sh`.
- Display detection uses `DISPLAY` or `WAYLAND_DISPLAY` environment variables.
### Windows
- NSIS installer configuration: `build/windows/nsis/project.nsi`
- MSIX package template: `build/windows/msix/template.xml`
- `hasDisplay()` always returns `true` on Windows.
## Coding standards
- **UK English** in all documentation and user-facing strings (colour, organisation, centre).
- **Strict typing** -- all Go functions have explicit parameter and return types.
- **Formatting** -- run `core go fmt` before committing.
- **Linting** -- run `core go lint` to catch issues.
- **Licence** -- EUPL-1.2. Include the copyright header where appropriate.
## Commit conventions
Use conventional commits:
```
type(scope): description
```
Include the co-author line:
```
Co-Authored-By: Virgil <virgil@lethean.io>
```

97
docs/index.md Normal file
View file

@ -0,0 +1,97 @@
---
title: Core IDE
description: A native desktop development environment and headless CI job runner built with Wails 3 and Angular, providing MCP-driven webview automation and Forgejo-integrated agent dispatch.
---
# Core IDE
Core IDE is a native desktop application that serves two roles:
1. **GUI mode** -- a Wails 3 desktop application with an Angular frontend, system tray panel, and an embedded MCP HTTP server that exposes webview automation tools (DOM inspection, JavaScript execution, screenshots, network monitoring, and more).
2. **Headless mode** -- a daemon that polls Forgejo repositories for actionable signals (draft PRs, review state, fix commands) and dispatches work to AI agents via the Clotho spinner, with a minimal MCP HTTP interface for remote control.
Both modes listen on `127.0.0.1:9877` and expose `/health`, `/mcp`, `/mcp/tools`, and `/mcp/call` endpoints.
## Quick start
### Prerequisites
- Go 1.26+
- Node.js 22+ and npm
- Wails 3 CLI (`wails3`)
- Access to the Go workspace at `~/Code/go.work` (the module uses `replace` directives for local siblings)
### Development
```bash
cd /path/to/core/ide
# Install frontend dependencies and start dev mode (hot-reload)
wails3 dev
# Or build a production binary
core build # uses .core/build.yaml
wails3 build # alternative, uses build/config.yml
```
### Headless mode
```bash
# Run as a headless daemon (no GUI required)
./bin/core-ide --headless
# Dry-run mode -- logs what would happen without side-effects
./bin/core-ide --headless --dry-run
# Specify which repos to poll (comma-separated)
CORE_REPOS=host-uk/core,host-uk/core-php ./bin/core-ide --headless
```
A systemd unit is provided at `build/linux/core-ide.service` for running headless mode as a system service.
## Package layout
| Path | Purpose |
|------|---------|
| `main.go` | Entry point -- decides GUI or headless based on `--headless` flag / display availability |
| `mcp_bridge.go` | `MCPBridge` -- Wails service that starts the MCP HTTP server, WebSocket hub, and webview tool dispatcher (GUI mode) |
| `claude_bridge.go` | `ClaudeBridge` -- WebSocket relay between GUI clients and an upstream MCP core server |
| `headless.go` | `startHeadless()` -- daemon with Forgejo poller, job handlers, agent dispatch, PID file, and health endpoint |
| `headless_mcp.go` | `startHeadlessMCP()` -- minimal MCP HTTP server for headless mode (job status, dry-run toggle, manual poll trigger) |
| `greetservice.go` | `GreetService` -- sample Wails-bound service |
| `icons/` | Embedded PNG assets for system tray (macOS template icon, default icon) |
| `frontend/` | Angular 20 application (standalone components, SCSS, Wails runtime bindings) |
| `frontend/src/app/pages/tray/` | `TrayComponent` -- compact system tray panel (380x480 frameless window) |
| `frontend/src/app/pages/ide/` | `IdeComponent` -- full IDE layout with sidebar, dashboard, file explorer, terminal placeholders |
| `frontend/src/app/components/sidebar/` | `SidebarComponent` -- icon-based navigation rail |
| `frontend/bindings/` | Auto-generated TypeScript bindings for Go services |
| `build/` | Platform-specific build configuration (macOS plist, Windows NSIS/MSIX, Linux systemd/AppImage/nfpm) |
| `.core/build.yaml` | `core build` configuration (Wails type, CGO enabled, cross-compilation targets) |
| `build/config.yml` | Wails 3 project configuration (app metadata, dev mode settings, file associations) |
## Dependencies
### Go modules
| Module | Role |
|--------|------|
| `forge.lthn.ai/core/go` | Core framework -- config, forge client, job runner, agent CI |
| `forge.lthn.ai/core/go-process` | Daemon utilities (PID file, health check endpoint) |
| `forge.lthn.ai/core/gui` | WebView service (`pkg/webview`) and WebSocket hub (`pkg/ws`) |
| `github.com/wailsapp/wails/v3` | Native desktop application framework |
| `github.com/gorilla/websocket` | WebSocket client for the Claude bridge |
All three `forge.lthn.ai` dependencies are resolved via `replace` directives pointing to sibling directories (`../go`, `../go-process`, `../gui`).
### Frontend
| Package | Role |
|---------|------|
| `@angular/core` ^21 | Component framework |
| `@wailsio/runtime` 3.0.0-alpha.72 | Go/JS bridge (events, method calls) |
| `rxjs` ~7.8 | Reactive extensions |
## Licence
EUPL-1.2. See the copyright notice in `build/config.yml` and `build/darwin/Info.plist`.