一键导入
dev-flow
Guidelines and rules for developing in the codebase, including architecture principles, package structure, API spec conventions, and testing practices.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Guidelines and rules for developing in the codebase, including architecture principles, package structure, API spec conventions, and testing practices.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | dev-flow |
| description | Guidelines and rules for developing in the codebase, including architecture principles, package structure, API spec conventions, and testing practices. |
Invoke this skill whenever building, modifying, or reviewing code in this project. This includes adding features, creating new endpoints, adding MCP tools, writing domain logic, defining ports/adapters, or modifying API specs.
Tech stack: Go (backend, hexagonal architecture), SQLite (default storage), TypeSpec (API contract definitions), embedded frontend in single binary.
Before writing any Go code, consult docs/hexagonal-architecture/ for the full guide. The critical rules are:
ALLOWED FORBIDDEN
─────────────────────── ───────────────────────
domain → (nothing) domain → ports
ports → domain ports → adapters
app → ports, domain app → adapters, handlers
adapters → ports, domain adapters → app, handlers, other adapters
handlers → app, domain handlers → adapters
services → everything (services is the composition root)
If you find yourself importing an adapter inside app/, or app/ inside an adapter — stop. Define a port interface, implement it in an adapter, inject through the composition root.
| Package | Can import | Cannot import |
|---|---|---|
domain/ | standard library only | everything else |
ports/ | domain/ | adapters/, app/, handlers/ |
app/ | ports/, domain/ | adapters/, handlers/ |
adapters/ | ports/, domain/, clients/ | app/, handlers/ |
handlers/ | app/, domain/, common/ | adapters/ |
services/ | all internal packages | — |
cmd/ | services/, config/ | — |
cmd/ → Entry points (main.go)
internal/
domain/ → Pure business entities, value objects, rules (NO external imports)
ports/ → Interface definitions with port-specific DTOs
<port_name>/
interface.go → Interface definition
types.go → Port-specific param/result DTOs
adapters/ → Concrete implementations of ports
<adapter_name>/
<impl>.go → Implementation
type_conversion.go → Mapping between port DTOs and infra types
app/ → Application layer (use cases)
commands/ → Write operations (each file = one command)
queries/ → Read operations (each file = one query)
decorators/ → Cross-cutting wrappers (logging, tracing, caching, errors)
executors/ → Generic Executor interfaces
<name>_app.go → Application struct grouping commands & queries
handlers/ → Primary adapters (HTTP/gRPC/CLI/event translation)
<handler_name>/
<service>.go
type_conversion.go
interceptors/ → Middleware (auth, logging, correlation ID)
clients/ → Low-level infrastructure client wrappers
common/ → Shared utilities (errors, logger, metrics)
config/ → Configuration structs, loaded from env vars
services/ → Composition root (dependency injection wiring)
resources/test/ → Test infrastructure (containers, seed, mocks)
| Command | What it does |
|---|---|
make generate | Full pipeline: TypeSpec → OpenAPI → Go stubs → TS client |
make generate-spec | Compile TypeSpec to OpenAPI YAML |
make generate-go | Generate Go server interface + types from OpenAPI |
make generate-ts | Generate TypeScript API client from OpenAPI |
make build | Build the Go server binary |
Executor pattern — All use cases implement a generic interface:
type Executor[Params any] interface {
Execute(ctx context.Context, params Params) error
}
type ExecutorWithReturn[Params, Result any] interface {
Execute(ctx context.Context, params Params) (Result, error)
}
Application struct — Groups commands and queries into a single injectable object:
type AdminApp struct {
Commands AdminCommands
Queries AdminQueries
}
Decorator pattern — Wrap executors for logging, tracing, caching, error handling. Applied in the composition root. Order matters (outermost executes first).
Compile-time interface checks — Every adapter must include:
var _ portpkg.SomeInterface = (*AdapterImpl)(nil)
Type conversion — Each adapter and handler has its own type_conversion.go. Never leak infrastructure types into ports or domain.
Manual dependency injection — No DI frameworks. The composition root (internal/services/) is the only place that knows all layers.
Error handling — Use AppError with error codes (NotFound, InvalidInput, Conflict, etc.) from internal/common/errors/. Handlers map codes to transport status codes. The error handler decorator wraps unexpected errors as Internal.
Configuration — All config from environment variables, loaded once at startup, injected through composition root. Adapters receive only what they need.
resources/test/mock/. Use compile-time interface checks.Migration files live in internal/adapters/sqlite_db/migrations/ and use goose format.
Every migration file MUST include -- +goose Up and -- +goose Down directives. Without these, goose cannot parse the file and the server will fail to start.
-- +goose Up
CREATE TABLE example (
id TEXT PRIMARY KEY,
name TEXT NOT NULL
);
-- +goose Down
DROP TABLE example;
Key rules:
-- +goose Up-- +goose Down section for rollback-- +goose Up are fine (no need for StatementBegin/StatementEnd unless using procedural SQL)CREATE TABLE IF NOT EXISTS — goose tracks applied migrations, so idempotent DDL is unnecessaryNNN_description.sql (e.g., 009_create_agent_tools.sql)Before adding or modifying API endpoints, consult docs/api-spec/01-typespec-guide.md for the full TypeSpec reference.
All TypeSpec files live in spec/:
spec/main.tsp — Entry point, service metadata, imports routesspec/models/ — Data model definitionsspec/routes/ — Route definitions using modelsspec/tsp-output/schema/openapi.yaml — Generated OpenAPI outputEvery API change follows this strict sequence. Do NOT skip steps or implement code before the spec is updated and stubs are generated.
spec/models/<feature>.tsp and routes in spec/routes/<feature>.tsp. Import new route files in spec/main.tsp.make generate-spec (compiles TypeSpec to spec/tsp-output/schema/openapi.yaml).make generate-go (generates internal/api/gen/server.gen.go and types.gen.go from OpenAPI) and make generate-ts (generates TypeScript client in ui/). Or run make generate to do all three steps at once.ServerInterface.Key rules:
ServerInterface in internal/api/gen/server.gen.go is the source of truth for HTTP handler signatures. Never hand-write route registrations.internal/api/gen/*.gen.go) must NEVER be manually edited. They are overwritten on each generation.make generate) before updating Go code, so generated types stay in sync.internal/handlers/ implement gen.ServerInterface. The composition root registers them via gen.HandlerFromMux().ApiApi.ModelsApi.Routes@tag("<Feature>") namespaces@summary() and JSDoc comments for documentationmodels/using Api.Models;// Model with enum
enum Status { Active: "active", Inactive: "inactive" }
model Thing { id: string; name: string; status: Status; }
// CRUD routes
@tag("Things")
namespace Things {
@get @route("/things") @summary("List things")
op list(): Thing[];
@get @route("/things/{id}") @summary("Get thing")
op get(@path id: string): Thing | { @statusCode statusCode: 404; @body body: ErrorResponse; };
@post @route("/things") @summary("Create thing")
op create(@body body: CreateThingRequest): { @statusCode statusCode: 201; @body body: Thing; };
@delete @route("/things/{id}") @summary("Delete thing")
op delete(@path id: string): { @statusCode statusCode: 204; };
}
github.com/modelcontextprotocol/go-sdk/mcpIn addition to the HTTP API, the system must expose command/query functionality as MCP (Model Context Protocol) tools. MCP tools are a separate primary adapter — they follow the same hexagonal architecture rules as HTTP handlers but are hand-written (no code generation).
All MCP tools live in internal/handlers/mcp_handler/, organized by domain:
internal/handlers/mcp_handler/
handler.go → Handler struct, NewHandler(), HTTPHandler() (server init + registration)
health_tools.go → Health check tools
Each tool file follows a consistent three-part structure:
package mcphandler
// 1. Input/Output DTOs — use json + jsonschema struct tags
type CreateThingInput struct {
Name string `json:"name" jsonschema:"name of the thing to create"`
Status string `json:"status" jsonschema:"initial status (active or inactive)"`
}
type CreateThingOutput struct {
ID string `json:"id"`
Name string `json:"name"`
}
// 2. Tool registration — called from handler.go's HTTPHandler()
func (h *Handler) registerThingTools(s *mcp.Server) {
mcp.AddTool(s, &mcp.Tool{
Name: "thing_create",
Description: "Create a new thing with the given name and status.",
}, h.thingCreate)
mcp.AddTool(s, &mcp.Tool{
Name: "thing_list",
Description: "List all things.",
}, h.thingList)
}
// 3. Tool handlers — call app layer commands/queries
func (h *Handler) thingCreate(ctx context.Context, _ *mcp.CallToolRequest, input CreateThingInput) (*mcp.CallToolResult, CreateThingOutput, error) {
result, err := h.thingApp.Commands.Create.Execute(ctx, commands.CreateThingParams{
Name: input.Name,
Status: input.Status,
})
if err != nil {
return nil, CreateThingOutput{}, fmt.Errorf("create thing failed: %w", err)
}
return nil, CreateThingOutput{ID: result.ID, Name: result.Name}, nil
}
snake_case with domain prefix (e.g., auth_login, agent_create, provider_list)jsonschema struct tag provides descriptions for each field; the MCP SDK auto-generates the JSON Schema from these tagsapp.Commands / app.Queries — never call adapters directlyHandler struct in handler.go and the NewHandler() constructor/mcp via mcp.NewStreamableHTTPHandler in internal/services/server.goAUTH_CREDENTIALS is configured, the MCP endpoint is wrapped with HTTP basic auth automaticallyinternal/handlers/mcp_handler/<domain>_tools.goh.register<Domain>Tools(server) call in HTTPHandler()NewHandler() in handler.go, then wire them in internal/services/server.gospec/models/<feature>.tsp + spec/routes/<feature>.tsp)spec/main.tsp if it's a new filemake generate to compile spec → generate OpenAPI → generate Go server stubs + TS clientServerInterface in internal/api/gen/server.gen.go has the new methodsinternal/domain/ (stdlib only, no external deps)internal/ports/<name>/ (imports domain only)internal/adapters/<name>/ with compile-time checks (imports ports + domain)internal/app/commands/ or internal/app/queries/ (imports ports + domain)internal/app/decorators/ (imports app + executors)type_conversion.go in internal/handlers/<name>/ (imports app + gen + common)internal/handlers/mcp_handler/<domain>_tools.go if the feature should be exposed via MCP (imports app + mcp SDK)internal/services/ composition root (imports all layers)go build ./... and go vet ./...website/docs/)Update user-facing documentation in website/docs/ to reflect the feature change.
Rules:
website/docs/<category>/ folder (e.g., guides/, api/, configuration/)._category_.json if adding a new folder.Conventions:
sidebars.ts uses autogenerated). No manual sidebar edits needed._category_.json with label and position fields.sidebar_position, title) to control page ordering.Checklist:
_category_.jsonwebsite/docs/<category>/