1- <p align =" center " >
2- <img src =" assets/openctrl.png " alt =" OpenCtrl banner " width =" 50% " >
3- </p >
4-
5- <p align =" center " >
6- <a href =" docs/master.md " ><img alt =" API v2 " src =" https://img.shields.io/badge/API-v2-14b8a6?style=flat-square " ></a >
7- <a href =" docs/master.md " ><img alt =" Events SSE " src =" https://img.shields.io/badge/events-SSE-f59e0b?style=flat-square " ></a >
8- <img alt =" Go 1.26.4 " src =" https://img.shields.io/badge/Go-1.26.4-00ADD8?style=flat-square& ; logo=go& ; logoColor=white " >
9- <a href =" LICENSE " ><img alt =" License BSD 3-Clause " src =" https://img.shields.io/badge/license-BSD--3--Clause-0f172a?style=flat-square " ></a >
10- </p >
11-
12- OpenCtrl is a focused control-plane master for supervising URL-defined
13- instances. It stores instance definitions, launches a compatible runtime binary
14- for each managed instance, exposes a versioned REST API, and streams live
15- lifecycle, log, and metric updates over Server-Sent Events.
16-
17- It is intentionally narrow: the master owns orchestration, persistence,
18- authentication, and observability; runtime binaries own protocol-specific work.
19-
20- ## Contents
21-
22- - [ Highlights] ( #highlights )
23- - [ Architecture] ( #architecture )
24- - [ Quick Start] ( #quick-start )
25- - [ Master URL] ( #master-url )
26- - [ API Surface] ( #api-surface )
27- - [ Runtime Contract] ( #runtime-contract )
28- - [ State and Security] ( #state-and-security )
29- - [ Release] ( #release )
30- - [ Documentation] ( #documentation )
31-
32- ## Highlights
33-
34- | Capability | What it provides |
35- | --- | --- |
36- | URL-defined instances | Every managed workload is represented by one URL and one generated instance ID. |
37- | Process supervision | The master starts, stops, restarts, and deletes child processes through a stable runtime contract. |
38- | Versioned control API | REST endpoints are served under ` /api/v2 ` or a custom versioned prefix. |
39- | Live event stream | SSE publishes initial state, lifecycle changes, child logs, metric checkpoints, deletions, and shutdown events. |
40- | Durable local state | Instance definitions and the API key are persisted beside the executable with a backup file. |
41- | Runtime neutrality | The master does not special-case child protocols; compatible binaries validate and execute their own URLs. |
42- | TLS-ready operation | HTTP, self-signed TLS, and file-backed TLS certificate modes are selected from the master URL. |
43-
44- ## Architecture
45-
46- ``` mermaid
47- flowchart LR
48- client["API clients"]
49- events["SSE subscribers"]
50- master["OpenCtrl master"]
51- state["gob state"]
52- runtime["runtime binary"]
53- instA["instance URL"]
54- instB["instance URL"]
55-
56- client -->|"REST + X-API-Key"| master
57- master -->|"event: instance"| events
58- master <-->|"load / save"| state
59- master -->|"spawn <runtime> <url>"| runtime
60- runtime --> instA
61- runtime --> instB
62- ```
1+ # OpenCtrl
2+
3+ OpenCtrl is an advanced control-plane master for URL-defined runtime instances.
634
64- The master process provides the control plane. Child processes stay in the
65- foreground, emit logs and optional checkpoints, and exit when the master stops
66- them.
5+ It stores instance definitions, supervises child processes, exposes a versioned
6+ HTTP API, and streams lifecycle, log, and metric updates over Server-Sent
7+ Events. The master stays generic: orchestration belongs here; protocol behavior
8+ belongs to the runtime binary.
679
68- ## Quick Start
10+ ## Design
6911
70- Build the master:
12+ - URL-first instance configuration
13+ - Runtime-neutral process supervision
14+ - Versioned REST API under ` /api/v2 `
15+ - Server-Sent Events for live state
16+ - Local durable state with backup
17+ - HTTP, self-signed TLS, or certificate-backed TLS
18+
19+ ## Build
7120
7221``` sh
7322go build -trimpath -o ./bin/openctrl ./cmd/openctrl
7423```
7524
76- Start a local control plane:
25+ ## Run
7726
7827``` sh
7928./bin/openctrl ' master://127.0.0.1:8080'
8029```
8130
82- The master prints an API key on startup :
31+ On first start, OpenCtrl prints an API key:
8332
8433``` text
8534Master.run: API key created: <api-key>
8635```
8736
88- Use the key with the versioned API:
37+ Use it with the API:
8938
9039``` sh
9140BASE=' http://127.0.0.1:8080/api/v2'
@@ -95,7 +44,8 @@ curl -H "X-API-Key: ${API_KEY}" "${BASE}/info"
9544curl -H " X-API-Key: ${API_KEY} " " ${BASE} /instances"
9645```
9746
98- Run managed instances through a compatible runtime binary:
47+ To supervise non-` master ` instance schemes, point the master at a compatible
48+ runtime binary:
9949
10050``` sh
10151./bin/openctrl ' master://127.0.0.1:8080?bin=/opt/openctrl/runtime'
@@ -116,109 +66,79 @@ curl -X POST "${BASE}/instances" \
11666master://<host>:<port>[/prefix][?<query>]
11767```
11868
119- The host and port become the listen address. The optional path becomes the API
120- prefix, and the API version is appended automatically.
69+ The host and port become the listen address. The path becomes the API prefix,
70+ with the API version appended automatically.
12171
122- | Master URL | API base |
72+ | URL | API base |
12373| --- | --- |
12474| ` master://127.0.0.1:8080 ` | ` http://127.0.0.1:8080/api/v2 ` |
12575| ` master://127.0.0.1:8080/control ` | ` http://127.0.0.1:8080/control/v2 ` |
12676| ` master://127.0.0.1:8443?tls=1 ` | ` https://127.0.0.1:8443/api/v2 ` |
12777
128- | Parameter | Values | Default | Purpose |
129- | --- | --- | --- | --- |
130- | ` tls ` | ` 0 ` , ` 1 ` , ` 2 ` | ` 0 ` | Select HTTP, self-signed TLS, or certificate-backed TLS . |
131- | ` crt ` | file path | empty | Certificate file used with ` tls=2 ` . |
132- | ` key ` | file path | empty | Private key file used with ` tls=2 ` . |
133- | ` bin ` | file path | current executable | Runtime binary used to launch managed instances. |
78+ | Query | Description |
79+ | --- | --- |
80+ | ` tls=0 ` | Plain HTTP. |
81+ | ` tls=1 ` | Self-signed TLS . |
82+ | ` tls=2&crt=<path>& key=<path> ` | Certificate-backed TLS . |
83+ | ` bin=<path> ` | Runtime binary used for managed instances. |
13484
135- ## API Surface
85+ ## API
13686
137- All protected requests must include :
87+ All protected requests require :
13888
13989``` text
14090X-API-Key: <api-key>
14191```
14292
143- Core endpoints:
144-
145- | Method | Path | Description |
93+ | Method | Path | Purpose |
14694| --- | --- | --- |
147- | ` GET ` | ` /info ` | Return master identity, runtime configuration, uptime, and system metrics . |
95+ | ` GET ` | ` /info ` | Read master identity and runtime information . |
14896| ` POST ` | ` /info ` | Set the master alias. |
149- | ` GET ` | ` /instances ` | Return all instances, including the internal API-key instance. |
150- | ` POST ` | ` /instances ` | Create and asynchronously start an instance. |
151- | ` GET ` | ` /instances/{id} ` | Return one instance. |
152- | ` PATCH ` | ` /instances/{id} ` | Update metadata, restart policy, or lifecycle action. |
153- | ` PUT ` | ` /instances/{id} ` | Replace the instance URL and restart the instance. |
154- | ` DELETE ` | ` /instances/{id} ` | Stop and delete the instance. |
155- | ` GET ` | ` /events ` | Open the Server-Sent Events stream. |
156- | ` GET ` | ` /tcping?target=host:port ` | Test TCP reachability from the master process. |
157-
158- Lifecycle actions accepted by ` PATCH /instances/{id} ` :
159-
160- | Action | Effect |
161- | --- | --- |
162- | ` start ` | Start a stopped child process. |
163- | ` stop ` | Stop an active child process. |
164- | ` restart ` | Stop and start the child process. |
165- | ` reset ` | Reset runtime byte counters. |
97+ | ` GET ` | ` /instances ` | List instances. |
98+ | ` POST ` | ` /instances ` | Create and start an instance. |
99+ | ` GET ` | ` /instances/{id} ` | Read one instance. |
100+ | ` PATCH ` | ` /instances/{id} ` | Update metadata, policy, or lifecycle action. |
101+ | ` PUT ` | ` /instances/{id} ` | Replace the instance URL. |
102+ | ` DELETE ` | ` /instances/{id} ` | Stop and delete an instance. |
103+ | ` GET ` | ` /events ` | Subscribe to instance events. |
104+ | ` GET ` | ` /tcping?target=host:port ` | Test TCP reachability. |
105+
106+ ` PATCH /instances/{id} ` accepts ` start ` , ` stop ` , ` restart ` , and ` reset ` .
166107
167- SSE frames use the event name ` instance ` :
108+ SSE messages use the event name ` instance ` :
168109
169110``` text
170111event: instance
171112data: {"type":"update","time":"2026-06-08T12:00:00Z","instance":{...},"logs":""}
172113```
173114
174- Event payload types are ` initial ` , ` create ` , ` update ` , ` delete ` , ` log ` , and
115+ Event types are ` initial ` , ` create ` , ` update ` , ` delete ` , ` log ` , and
175116` shutdown ` .
176117
177118## Runtime Contract
178119
179- OpenCtrl supervises runtime binaries with a small process contract :
120+ OpenCtrl launches managed instances as :
180121
181122``` text
182123<runtime-binary> <instance-url>
183124```
184125
185- For non-` master ` instance schemes, point ` bin ` at a binary that understands
186- those schemes. The master treats child URLs as opaque runtime configuration.
187-
188- Runtime binaries MUST:
189-
190- - accept the full instance URL as the first positional argument;
191- - reject invalid configuration before starting long-running work;
192- - stay in the foreground while the instance is active;
193- - handle termination and exit within the master's 5-second grace period when
194- possible;
195- - return a non-zero exit code for failures that should place the instance in
196- ` error ` ;
197- - avoid printing secrets from URLs, headers, keys, or tokens.
198-
199- Runtime binaries SHOULD:
126+ Runtime binaries must accept the full instance URL as the first argument, stay
127+ in the foreground while active, reject invalid configuration before long-running
128+ work starts, handle termination promptly, and return a non-zero exit code for
129+ failures that should move the instance to ` error ` .
200130
201- - emit newline-delimited logs to stdout or stderr;
202- - emit checkpoints after the service is ready when metrics are available;
203- - keep byte counters monotonic for the life of the process.
204-
205- Runtime binaries MAY:
206-
207- - define their own URL schemes and query parameters;
208- - omit checkpoints when metrics are not meaningful;
209- - print ordinary operational logs that should be visible to API clients.
210-
211- Checkpoint format:
131+ Runtime binaries should write newline-delimited logs to stdout or stderr. They
132+ may emit checkpoints for metrics:
212133
213134``` text
214135CHECK_POINT|MODE=<n>|PING=<n>ms|POOL=<n>|TCPS=<n>|UDPS=<n>|TCPRX=<bytes>|TCPTX=<bytes>|UDPRX=<bytes>|UDPTX=<bytes>
215136```
216137
217- Non-checkpoint child output is forwarded to stdout and published as ` log `
218- events. If a line contains the substring ` ERROR ` , the instance is marked
219- ` error ` .
138+ Non-checkpoint output is forwarded to stdout and published as ` log ` events. A
139+ line containing ` ERROR ` marks the instance as ` error ` .
220140
221- ## State and Security
141+ ## State
222142
223143State is stored beside the executable:
224144
@@ -227,37 +147,23 @@ State is stored beside the executable:
227147<executable-directory>/gob/openctrl.gob.backup
228148```
229149
230- Operational notes:
231-
232- - protect the API key printed by the master;
233- - protect the state directory because ` openctrl.gob ` stores the API key;
234- - use ` tls=2 ` with a trusted certificate outside local-only deployments;
235- - use a trusted ` bin ` path because managed instances execute that binary;
236- - treat instance URLs as secrets when they contain credentials or tokens;
237- - account for permissive CORS headers when exposing the API across origins.
150+ Protect the API key, state directory, runtime binary path, and instance URLs.
151+ Use ` tls=2 ` for networked deployments.
238152
239153## Release
240154
241- Build a local binary:
242-
243- ``` sh
244- go build -trimpath -o ./bin/openctrl ./cmd/openctrl
245- ```
246-
247- Embed a version string:
248-
249155``` sh
250156go build -trimpath \
251157 -ldflags=" -s -w -X main.version=$VERSION " \
252158 -o ./bin/openctrl ./cmd/openctrl
253159```
254160
255- Tagged releases are built by GoReleaser for Darwin, FreeBSD, Linux, and
161+ Tagged releases are built with GoReleaser for Darwin, FreeBSD, Linux, and
256162Windows on ` amd64 ` and ` arm64 ` .
257163
258164## Documentation
259165
260- - [ Master API and runtime contract] ( docs/master.md )
166+ See [ docs/master.md ] ( docs/master.md ) for the full API and runtime contract.
261167
262168## License
263169
0 commit comments