ActonOS API Development Skill
SkillDev toolsSkill for developing REST API endpoints in internal/server/. Covers routing, request validation, WebSocket streaming, and API conventions.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the ActonOS API Development Skill skill
What this skill tells your AI
The instructions your AI receives, as published by actonos/actonos in .agents/skills/actonos-api-dev/SKILL.md and read by ahel’s review.
Use this skill when creating or modifying REST API endpoints in the internal/server/ package.
1. Package Overview
internal/server/
├── router.go # Chi router setup, global & auth middlewares, route tree
├── api_auth.go # Setup, login, logout, password change, auth status
├── api_dashboard.go # Dashboard aggregate metrics & summaries
├── api_agent.go # Agent CRUD, start/stop, chat, soul, memory-md, memories (pin/importance), cron
├── api_tasks.go # Autonomous Task matrix CRUD, Heartbeat config & manual pulse triggers
├── api_conversations.go # Chat conversations and message history
├── api_plugins.go # WASM plugin upload, enable/disable, logs, configuration & vault secrets
├── api_vault.go # Hardware-bound vault secret management
├── api_integrations.go # Channel accounts, pairing codes, sender authorization
├── api_tools.go # MCP servers, skills, tool execution, hub marketplace
├── api_workspace.go # Workspace file browser, read/write/mkdir/upload
├── api_system.go # Metrics, LLM health & retune, token usage ledger history, keys, identity, HAL
├── api_setup.go # Legacy/standalone setup endpoints
├── layered_fs.go # Layered filesystem (/data/overrides/ → go:embed fallback)
├── static.go # Embedded static asset server
└── server_test.go # Comprehensive endpoint test suite
2. HTTP Framework & Conventions
Base URL & Versioning
- Current Base URL:
/api(all routes are prefixed with/api) - Do not use
/api/v1/prefix until v1.0.0 is officially released.
Router Engine
ActonOS uses Chi v5 with standard library net/http:
import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
Standard Response Envelope
Success (s.respondJSON(w, http.StatusOK, data)):
{
"data": { ... }
}
Error (s.respondError(w, http.StatusBadRequest, "INVALID_REQUEST", "description")):
{
"error": {
"code": "INVALID_REQUEST",
"message": "Human-readable explanation of error"
}
}
Common Helper Methods in Server
// 1. Respond with JSON data wrapped in {"data": ...}
func (s *Server) respondJSON(w http.ResponseWriter, status int, data any)
// 2. Respond with standard error envelope wrapped in {"error": {"code": ..., "message": ...}}
func (s *Server) respondError(w http.ResponseWriter, status int, code, message string)
// 3. Decode request body with 1MB safety limit
func (s *Server) decodeJSON(r *http.Request, v any) error
3. Route Organization & Authentication
Public Routes
GET /api/healthGET /api/modelsGET /api/notifications/push/vapid-keyGET /api/auth/statusPOST /api/auth/setupPOST /api/auth/loginPOST /api/auth/logout
Protected Subsystems
All other routes are nested inside r.Group with r.Use(s.RequireAuthMiddleware). Requests must include Authorization: Bearer <token> in the HTTP headers when authentication is initialized.
4. Implementing a New API Endpoint
Step 1: Add Request & Response Structs
type UpdateSoulRequest struct {
SoulContent string `json:"soul_content"`
}
type SoulResponse struct {
AgentID string `json:"agent_id"`
Content string `json:"content"`
UpdatedAt string `json:"updated_at"`
}
Step 2: Implement Handler Method on *Server
func (s *Server) handleSaveSoul(w http.ResponseWriter, r *http.Request) {
agentID := chi.URLParam(r, "agentID")
if agentID == "" {
agentID = agent.DefaultSystemAgentID
}
var req UpdateSoulRequest
if err := s.decodeJSON(r, &req); err != nil {
s.respondError(w, http.StatusBadRequest, "INVALID_BODY", "failed to decode json body")
return
}
if err := s.profileMgr.SaveSoul(r.Context(), agentID, req.SoulContent); err != nil {
s.respondError(w, http.StatusInternalServerError, "SAVE_FAILED", err.Error())
return
}
s.respondJSON(w, http.StatusOK, SoulResponse{
AgentID: agentID,
Content: req.SoulContent,
UpdatedAt: time.Now().UTC().Format(time.RFC3339),
})
}
Step 3: Register Route in internal/server/router.go
r.Route("/agents", func(r chi.Router) {
// ...
r.Route("/{agentID}", func(r chi.Router) {
// ...
r.Put("/soul", s.handleSaveSoul)
})
})
Step 4: Update Documentation and TypeScript Types
- Add endpoint entry to
docs/API.md - Add route and handler to
.agents/rules/source-registry.md - Add client method to
web/src/lib/api.tsand interfaces toweb/src/lib/types.ts
5. Streaming Endpoints (SSE / Server-Sent Events)
For streaming LLM tokens, reasoning thoughts, and tool call progress:
func (s *Server) handleChatStream(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
if !ok {
s.respondError(w, http.StatusInternalServerError, "STREAMING_UNSUPPORTED", "streaming not supported")
return
}
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
eventChan := make(chan agent.AgentStreamEvent, 64)
go func() {
_, _ = s.engine.ExecuteStepStreamWithHistory(
r.Context(), agentID, msg, history, eventChan,
)
}()
for ev := range eventChan {
data, _ := json.Marshal(ev)
fmt.Fprintf(w, "event: %s\ndata: %s\n\n", ev.Type, data)
flusher.Flush()
}
}
The stream endpoint must flush live thought, token, tool_call,
tool_result, audit, done, and error events. It must not proxy to the
non-streaming JSON handler. Conversation messages are persisted before and
after the stream.
Realtime Operations WebSocket
GET /api/realtimeis a protected, same-origin WebSocket.- Browser authentication uses the HttpOnly
actonos_tokencookie set by setup/login; never put bearer tokens in WebSocket query strings. - Snapshots include hardware/Docker metrics, durable runs, pending approvals and token summaries.
- The stream is observation-only and must not expose an interactive shell or mutation channel.
6. Verification Checklist for API Changes
- Route is registered inside
router.go - Authentication middleware requirement is verified
- Error responses use standard
s.respondErrorwith appropriate HTTP status - TypeScript types in
web/src/lib/types.tsandapi.tsare synced -
docs/API.mdand.agents/rules/source-registry.mdare updated -
go test ./internal/server/...passes
7. Approval and Run APIs
api_approvals.goowns durable exact-action approval decisions.api_runs.goexposes durable run summaries and ordered execution events.- Authentication is not tool authorization. Execution handlers MUST call
ToolRegistry.Executeand return HTTP 202 forApprovalRequiredError. - MCP connection is a High-risk administrative action and requires approval.
- Preserve trace IDs through handler, engine, registry, approval, and audit calls.
- Workspace, skill, WASM, Hub, and restart mutations must use
requestAdminApprovaland exact dispatch fromapi_approvals.go. GET /api/system/audit/verifyis the canonical audit-chain integrity check.- Checkpointed approvals resume the same durable run; do not create a replacement.
- All server filesystem paths must derive from
Config.DataDir,Config.WorkspaceDir,Config.SkillsDir, orConfig.WASMDir; handlers must not assume the process working directory is the data root. - Provider credentials must use
Server.vault; never write API keys into JSON or.keyfiles. Preserve automatic legacy migration and fail closed without Vault. - SQLite backups must use
VACUUM INTOthrough the live database connection; never copy the main database file while WAL mode is active.
Signals
- GitHub stars
- 88
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
actonos-api-dev- Source
- github.com/actonos/actonos