Help us improve
Share bugs, ideas, or general feedback.
From assembly
Assembly-specific Go library patterns and conventions -- SQLite driver, migrations, session management, CSRF protection, rate limiting, CLI tooling, and testing. Use when choosing dependencies, configuring SQLite connection pools, setting up goose migrations, implementing SCS sessions, adding nosurf CSRF protection, building cobra CLI commands, or configuring httprate rate limiting for Assembly.
npx claudepluginhub design-machines-studio/depot --plugin assemblyHow this skill is triggered — by the user, by Claude, or both
Slash command
/assembly:golang-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Assembly's dependency choices and configuration patterns. Each library was selected for a specific reason -- understand the rationale before reaching for alternatives.
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Prepares production launches with a pre-launch checklist, monitoring setup, staged rollout planning, rollback strategies, and feature flag guidance.
Share bugs, ideas, or general feedback.
Assembly's dependency choices and configuration patterns. Each library was selected for a specific reason -- understand the rationale before reaching for alternatives.
CGO-based SQLite driver. Chosen over modernc.org/sqlite for better performance and wider community testing.
DSN with production pragmas:
dsn := "file:data/assembly.db?" +
"_journal_mode=WAL&" +
"_foreign_keys=on&" +
"_busy_timeout=5000&" +
"_synchronous=FULL&" // Legal data durability
"_cache_size=-32000&" + // 32MB
"_mmap_size=268435456&" + // 256MB
"_temp_store=MEMORY"
Connection pools:
readDB.SetMaxOpenConns(4) // Concurrent readers (WAL allows this)
writeDB.SetMaxOpenConns(1) // Single writer (SQLite limitation)
Transaction helper:
func (db *DB) WithTx(ctx context.Context, fn func(*sql.Tx) error) error
All multi-step mutations use WithTx. Number generation (resolution numbers, sequence IDs) happens INSIDE the transaction.
Timestamp-prefixed SQL files with Up/Down sections.
-- +goose Up
CREATE TABLE gov_proposals (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
-- +goose Down
DROP TABLE gov_proposals;
Embed and run at startup:
//go:embed migrations/*.sql
var migrations embed.FS
func RunMigrations(db *sql.DB) error {
goose.SetBaseFS(migrations)
return goose.Up(db, "migrations")
}
Pre-migration safety: auto cp assembly.db backups/pre-migrate-{timestamp}.db before running.
Wrapper around nats-server. See the nats-jetstream skill for full patterns. Key dependency versions:
github.com/delaneyj/toolbelt v0.9.xgithub.com/nats-io/nats-server/v2 v2.12.xgithub.com/nats-io/nats.go v1.49.xSession middleware with SQLite backend.
sessionManager := scs.New()
sessionManager.Store = sqlite3store.New(db)
sessionManager.Lifetime = 24 * time.Hour
sessionManager.IdleTimeout = 4 * time.Hour
sessionManager.Cookie.SameSite = http.SameSiteLaxMode
sessionManager.Cookie.Secure = true // production only
sessionManager.Cookie.HttpOnly = true
Key rules:
Double-submit cookie pattern.
r.Use(nosurf.NewPure)
Template delivery via meta tag:
<meta name="csrf-token" content="{{ .CSRFToken }}">
Datastar reads the token:
<form data-header.X-CSRF-Token="document.querySelector('meta[name=csrf-token]').content">
Exempt routes (configure in middleware):
/healthz/.well-known/assemblyvar rootCmd = &cobra.Command{
Use: "assembly",
Short: "Assembly cooperative governance platform",
}
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Start the HTTP server",
RunE: runServe,
}
func init() {
rootCmd.AddCommand(serveCmd)
rootCmd.AddCommand(migrateCmd)
rootCmd.AddCommand(seedCmd)
rootCmd.AddCommand(adminCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(backupCmd)
}
Commands:
assembly serve -- Start HTTP server (default)assembly admin create -- Headless install (--name, --email, --password-file)assembly admin reset-password -- CLI password reset (--email)assembly migrate -- Run pending goose migrationsassembly seed --demo -- Load Catalyst Cooperative demo data (dev only)assembly version -- Show version and install IDassembly backup -- Manual SQLite backupPassword security: ONLY via --password-file or --password-stdin. Never via env vars or CLI flags (prevents exposure in logs, docker inspect, /proc).
// Global
r.Use(httprate.LimitByIP(100, time.Minute))
// Login endpoint
r.With(httprate.LimitByIP(5, time.Minute)).Post("/login", handleLogin)
// SSE connections
r.With(httprate.LimitByIP(10, time.Minute)).Get("/sse/*", handleSSE)
| Endpoint | Limit | Window |
|---|---|---|
| Login | 5 | 1 minute |
| API (global) | 100 | 1 minute |
| SSE connections | 10 | 1 minute |
Events must publish AFTER tx.Commit(), never inside the transaction. If the transaction rolls back, a pre-commit event is a lie that corrupts downstream state (KV cache, SSE clients, audit trail).
// CORRECT — publish after commit
err := db.WithTx(ctx, func(tx *sql.Tx) error {
// ... mutations and audit write ...
return nil
})
if err != nil {
return err
}
deps.Events.Publish("assembly.gov.proposal.status_changed", envelope)
// WRONG — publish inside transaction
err := db.WithTx(ctx, func(tx *sql.Tx) error {
// ... mutations ...
deps.Events.Publish(...) // fires even if tx rolls back
return nil
})
Route middleware (RequireAuth, RequirePermission, RequireAdmin) handles RBAC -- "can this role access this route?" Object-level authorization (deps.Auth.Authorize()) handles ownership and status -- "can this member edit this specific proposal?"
Both are required for mutations. Route middleware alone is insufficient because it cannot check resource ownership, status gates, or group membership. Every mutation handler must call Authorize() even if the route already has permission middleware.
// Route: RequirePermission("governance.edit") gates the route
// Handler: Authorize() gates the specific resource
func (h *Handlers) UpdateProposal(w http.ResponseWriter, r *http.Request) {
// Route middleware already checked role permission
// Still need object-level auth:
if err := h.deps.Auth.Authorize(ctx, "proposal.edit", resource); err != nil {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// ... proceed with mutation
}
SQLite in tests:
func NewTestDB(t *testing.T) *sql.DB {
t.Helper()
dbPath := filepath.Join(t.TempDir(), "test.db")
db, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&_foreign_keys=on")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { db.Close() })
return db
}
Use t.TempDir() not :memory: -- WAL mode requires real files.
Interface injection for testability:
type Querier interface {
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
}
Services accept Querier interface, allowing both real DB and test stubs.
Table-driven tests for handlers:
tests := []struct {
name string
method string
path string
wantStatus int
}{
{"list proposals", "GET", "/governance/proposals", 200},
{"not found", "GET", "/governance/proposals/nonexistent", 404},
}
Test mutation flows end-to-end through the service layer. Mock the Dependencies struct interfaces and verify the full invariant sequence:
func TestCreateProposal(t *testing.T) {
db := NewTestDB(t)
auth := &MockAuthorizer{}
audit := &MockAuditWriter{}
events := &MockEventBus{}
svc := governance.NewService(governance.Deps{
DB: db, Auth: auth, Audit: audit, Events: events,
})
err := svc.CreateProposal(ctx, input)
require.NoError(t, err)
// Verify invariant sequence
assert.True(t, auth.AuthorizeCalled, "Authorize must be called")
assert.Equal(t, "proposal.create", auth.LastAction)
assert.True(t, audit.WriteCalled, "Audit entry must be written")
assert.True(t, events.PublishCalled, "Event must be published")
// Verify state change
got, _ := svc.GetProposal(ctx, input.ID)
assert.Equal(t, "draft", got.Status)
}
Focus: verify authorize was called with correct action, audit was written, event was published after commit, and DB state changed.
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self'")
srv := &http.Server{
ReadTimeout: 15 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
}
SSE handlers use http.ResponseController to extend WriteTimeout per-connection.
| Skill | Plugin | When to Load |
|---|---|---|
| development | assembly | Full Assembly development workflow |
| nats-jetstream | assembly | Embedded NATS patterns |
| governance | council | Domain requirements driving technical decisions |