Repository navigation
Naming
One name lets you guess the others (#127, #268): the same patterns everywhere — in decorators, the
CLI, traces, records, agboss describe and errors. What Components and the
CLI apply, in one place.
Every component's name is kebab-case, its qualifier in front and its kind last, and unique in the
application ([name.kind-suffix], [graph.duplicate-node-name]); its class is the same in
PascalCase:
| Kind | name |
Class |
|---|---|---|
@Application |
job-scout-application |
JobScoutApplication |
@Workflow |
screening-workflow |
ScreeningWorkflow |
@WorkflowStart / @WorkflowFinish
|
chat-workflow-start / chat-workflow-finish
|
ChatWorkflowStart / ChatWorkflowFinish
|
@Agent, @Router, @Action, @Arbiter
|
ranker-agent, main-router, enrich-company-action, in-range-arbiter
|
RankerAgent, MainRouter, … |
@Tool, @McpTool
|
save-shortlist-tool |
SaveShortlistTool |
@Rag |
jobs-rag (its tool: search-jobs-rag-tool) |
JobsRag |
@Budget, @ModelProvider, @HealthCheck, … |
tenant-daily-budget, openrouter-model-provider, crm-health-check
|
… |
DTO classes end with Dto (ScoreDto, [dto.name]); an @Injectable is named by its role —
…Service, …Repository, …Provider (#280) — and a field holding it after its type
(private readonly ordersService: OrdersService).
[name.kind-suffix] checks the name of every component and, for the @Application and each
@Budget, the class name as well: it must end with the kind in PascalCase (…Application,
…Budget). The classes of other kinds follow the same convention (RankerAgent, MainRouter)
without a check. A budget class named by what it limits but not by its kind fails assembly, with the
name to use:
import { Budget, BudgetPeriod, BudgetScope, type BudgetHandler } from "agboss";
import { usd, type Usd } from "agboss/units";
// [name.kind-suffix] class DailyLimit — name it DailyLimitBudget
@Budget({ name: "tenant-daily-budget", scope: BudgetScope.Tenant, period: BudgetPeriod.Day })
export class DailyLimit implements BudgetHandler {
maxSpend(): Usd {
return usd(40);
}
}The fix is the class name alone — the name was already right:
import { Budget, BudgetPeriod, BudgetScope, type BudgetHandler } from "agboss";
import { usd, type Usd } from "agboss/units";
@Budget({ name: "tenant-daily-budget", scope: BudgetScope.Tenant, period: BudgetPeriod.Day })
export class TenantDailyBudget implements BudgetHandler {
maxSpend(): Usd {
return usd(40);
}
}The same for the application: @Application({ name: "desk-application", … }) class Desk →
[name.kind-suffix] class Desk — name it DeskApplication.
A project's tool follows the kind-suffix rule like every other component: name: "save-shortlist-tool", kebab-case, checked at assembly with the name to use
("save_shortlist" on @Tool — name it "save-shortlist-tool"). A knowledge base's automatic tool is
search-<rag name>-tool; the framework's answer tools are answer-<dto>. Tools of an external MCP
server keep the names the server gives (read_text_file, in @McpServer({ tools })) — the model sees
the @McpTool that calls them. Every name a model sees fits the providers' limit (OpenAI, Anthropic,
Gemini): [a-zA-Z0-9_-], at most 64 characters ([tool.name-too-long], [tool.name-invalid]).
Tools.
| The definition | One execution |
|---|---|
@Workflow, @WorkflowStart, @WorkflowFinish, WorkflowRecord (name, version), WorkflowPauseQuestionDto
|
app.execute, ExecutionOutput (executionId), ExecutionContext, ExecutionId, ExecutionStatus, PausedExecution, ExecutionRecord
|
the hooks onExecutionStart, onExecutionPause, onExecutionResume, onExecutionEnd, onExecutionError, onExecutionRejected; ExecutionCancelledError
|
Nothing execution-time is named run…: result.executionId (not runId), IncompatibleResume
{ threadId, executionId }, executeAgent / AgentExecutionDeps / AgentExecutionOptions /
executionVersions for the lower-level loop.
A limit reads as what it is — usd(0.5), seconds(30), minutes(2) (agboss/units), never a bare
number, no Ms / Usd in names. Every timeout is one: @Tool({ timeout: seconds(5) }),
@ModelProvider({ timeout: minutes(2) }), @HealthCheck({ timeout: seconds(2) }); a join's waiting
limit is a different thing, its deadline (.joinQuorum({ min, deadline: seconds(30) })).
The command is agboss. Every name it takes is the full, kind-suffixed name — --start screening-workflow-start, --workflow job-scout-workflow, agboss generate agent ranker-agent,
--rag jobs-rag — so grep "screening-workflow-start" finds every use, CI scripts included. Nothing
is completed or guessed: a name not found is exit 2 with Did you mean "…"? and the list, and
nothing runs or is written. CLI.
AGBoss
- Home
- Delivery Pipeline
- Architecture
- Configuration
- Environments
- Workflow — the paths
- Path scope
- Workflow as a step
- Parallel — quorums and arbiters
- Routing patterns
- Rollback — declared compensation
- Routers
- Guards
- CLI — agboss
- App — @Application and createApp
- Several instances
- Health checks
- Context and Authorization
- Testing
- The test split
- Suites and Comparisons
- Eval suites — @EvalSuite
- Components
- Naming
- Standard DTOs
- Examples: job-scout, flow-patterns
- Agents — the loop
- Model providers
- Tools
- Knowledge bases (RAG)
- FinOps
- Tracing
- Observability
- Terns and evaluation
- Profiles and comparisons
- Pauses — pending, resume by id
- Pause seam
- Decisions (ADR)