Skip to main content

Chatticus

Stack

v1 uses one language for the product brain. Do not add a second implementation of the same behavior until the protocol is stable.

Choices

Layer Choice Why
Agent, worker, API TypeScript on Node 22, Hono, Pi-durable, OpenAI OpenAI first; computer use; MCP clients; short Lambda edges. The Python control plane was deleted from develop; staging and production run it until the develop to main promotion.
Web TypeScript, Next.js, CloudFront Chat, roster, computer preview, approvals
Computer image Ubuntu, Xvfb, Chromium, noVNC Same artifact on Fargate and local Docker
Data DynamoDB, S3, Secrets Manager Transcript, bots, and rules in DynamoDB; snapshots and files in S3; secrets out of the image. A relational instance is always on and would break scale-to-zero.
Cloud API Per-request HTTP front door plus server-sent events scoped to one turn No persistent sockets. Nothing bills while nobody is working. See Messaging. The streaming path is unmeasured; see Feasibility tests.
Queues and schedules SQS, EventBridge Turns and heartbeats on SQS. EventBridge for routine wake-ups, worker starts, and device push. Neither is in the token path.
AWS compute CDK. Computer hosts are Fargate (scale to 0). The control plane is per-request functions; placement is not settled. Thin-turn front doors are named development, staging, and production stacks. Lambda for request-shaped work, including a stream held for one turn. Never a load balancer in front of the API: the hourly floor exceeds the container it replaces. Promote develop to development, main to staging, and production only as a gated deploy.
BDD cucumber-js with TypeScript steps over shared features/ Gherkin Product narrative lives in Gherkin
IaC AWS CDK in TypeScript Same language as the web app; every AWS resource lives in infra/. No console or ad-hoc CLI creates.

LLM providers

v1 talks to OpenAI (Chat Completions or Responses API with function calling). The agent loop depends on a small provider interface so the rest of Chatticus does not import a vendor SDK.

Amazon Bedrock is the next provider to consider. Do not add other vendors until OpenAI turns work end to end.

Lambda

Yes: auth callbacks, inbound webhooks, EventBridge "wake a routine", cheap HTTP.

Also yes: holding one turn's server-sent event stream. A turn is request-shaped, seconds to minutes. Response streaming serves it, and the client reconnects with after=seq if a turn outlives the function's maximum duration.

No: computer use, VNC/display, anything that must hold a browser, and any connection scoped to a chat tab or a login session.

State the premise, because the rule gets cited past its reason. Lambda is excluded from these because it cannot hold a browser, a display, or a session-lifetime connection. A turn phase that does none of those does not touch the premise: a computerless worker running the pre-computer part of a model loop is allowed, and is not the control plane. See challenge 5 in Design challenges.

Rust

Not v1. Revisit a Rust worker daemon only if the TypeScript heartbeat process is too heavy on a Mac. Shared Gherkin is the door for that later.

Local development

docker-compose will run a local DynamoDB, the control plane, and one computer container so a laptop can be both the human surface and a local worker. AWS is not required to prove routing, approvals, or a model turn against a stub worker.

The Postgres service still in docker-compose.yml predates the DynamoDB decision and is unused. Remove it when the local control plane lands.