Extending KanbanAI
This guide is for contributors who want to add new capabilities (agents, listeners, routes) without breaking the existing layering betweencore/ and server/.
Architecture recap
core/:- Business logic, abstract repository interfaces, and data access contracts.
- Defines repository interfaces in
core/src/repos/interfaces.tsand type definitions incore/src/db/types.ts. - No framework or runtime-specific code; database-agnostic.
server/:- Hono app, Bun entrypoints, HTTP/WebSocket routes, adapters for core services.
- Owns Drizzle schema definitions in
server/src/db/schema/and implements concrete repositories inserver/src/repos/. - Event bus wiring and module-level READMEs (
server/src/*/README.md) describing each domain.
client/:- React + Vite UI that talks to the API + WebSockets and uses shared types from
shared/.
- React + Vite UI that talks to the API + WebSockets and uses shared types from
- Adding/expanding a
coreservice or listener. - Adding routes/handlers in
serverthat adapt HTTP/WebSockets tocore.
Adding a new agent
- Define the agent behavior in
core/src/agents:- Create a new folder (e.g.
core/src/agents/my-agent) implementing theAgentinterface fromcore/src/agents/types.ts. - Implement
runandresume, streaming messages via the provided emitter.
- Create a new folder (e.g.
- Add availability detection (optional but recommended):
- Implement an
availability(): Promise<boolean>method to check if required executables or dependencies are installed. - Use
locateExecutable()fromcore/src/agents/sdk/executable.tsfor CLI-based agents. - Agents without availability checks are registered unconditionally.
- Implement an
- Register in server via
server/src/agents/registry.ts:- Add your agent to the
ALL_AGENTSarray. - The server uses
initializeServerAgents()at startup to dynamically register only available agents. - Availability checks ensure agents are only registered when their dependencies are installed.
- Add your agent to the
- Expose to the UI:
- Once registered, the agent appears in the
/agentsendpoint response. - Add any agent-specific profile schema/validation as needed.
- Once registered, the agent appears in the
- Wire profiles (optional):
- If your agent needs custom profile schema, integrate with
core/agents/profilesand validate configs before use.
- If your agent needs custom profile schema, integrate with
availability() method returns false, preventing runtime errors when dependencies are missing.
Adding a new event listener
- Define event types in
core/src/events/types.tsif you are introducing a new event kind. - Publish events from the relevant service:
- Use the
AppEventBustopublishdomain events from core services.
- Use the
- Register listeners:
- Add a new listener module (or extend an existing one) under
core/src/*/listeners.ts. - Wire it into
registerEventListenersinserver/src/events/register.ts.
- Add a new listener module (or extend an existing one) under
- Broadcast over WebSockets (optional):
- If the event should reach clients in realtime, subscribe to it in
server/src/ws/listeners.tsand map it to a WebSocket message defined inshared/src/types/kanban.ts.
- If the event should reach clients in realtime, subscribe to it in
Adding a new HTTP route
- Add core functionality (if needed):
- Implement the underlying behavior in
core/(service or helper).
- Implement the underlying behavior in
- Create a router/handlers in
server/src:- Follow existing patterns in modules like
projects,attempts, orgithub. - Keep Hono handlers thin: parse/validate input, call
core, map results to JSON.
- Follow existing patterns in modules like
- Wire the router into
app.ts:- Route under
/api/v1with a clear prefix (e.g./my-feature).
- Route under
Where to read more
server/src/*/README.md– domain-specific docs for:- attempts, github, tasks, projects, git, fs, ws, editor, settings, agents.
docs/core/ai-attempts.md– how Attempts work end-to-end.docs/core/git-integration.md– git helpers and events.docs/core/agents-and-profiles.md– agents module and profiles.