01Application composition
Actions as the application contract
Define a named operation with validation, policies, resilience, transaction, audit, history, quotas, and observability. The business capability remains independent of how it reaches the system.
02Service boundaries
Bind the right transport
Expose application actions over HTTP, NATS, cron, and workers. The same capability can serve an API, an event subscriber, a background job, or a scheduled operation.
03System building blocks
Build multi-tenant systems deliberately
Use tenant-aware authorisation, roles, features, encryption, audit chains, transactional persistence, domain events, and operational tooling as reusable architecture components.
Evidence in source code
Named actions. Transport boundaries. System context.
These compact examples show the engineering assets behind our service work: composing business capabilities, connecting the delivery mechanism, and keeping policies, tenants, data, events, and operational context with the application action.
createInvoice := action.New("invoices.create", handleCreateInvoice).
Route(
thttp.POST("/v1/invoices"),
tcli.Command("invoices create", "Generate a new invoice"),
tmcp.Tool("create_invoice"), // Tool for AI Agents
).
RequireAuth().
RequireTenant().
RequireRole("accountant").
Idempotent().
Timeout(3 * time.Second).
Retry(3, action.ExponentialJitter(50*time.Millisecond, time.Second)).
Transactional(db).
Audited(auditLogger, "billing", detailsFn).
Build()
System composition by design
Use technical foundations to reduce delivery risk, not to constrain the client.
We use the Framework when a named capability must serve an HTTP endpoint, a NATS subscription, a scheduled operation, or a worker. If another approach is better, we choose that.
Next step
Keep service logic close to the system that must evolve.
Treat the source code as technical evidence, then bring the architecture or delivery problem we should solve.