Build agent-step LangGraph agents — a ReAct agent fronted by one batching tool over a deterministic flow-controller runner (vendored and versioned; agent-step 3.0.1). Bootstrap a project (runner library + streaming CLI + graph/state/prompt scaffold + the required local sandbox service), then add domain tools declaratively: each action declares its params, prereqs and verdict ROWS — summary, doctrine, state write, effects, one authority per outcome — and its executor just names the verdict. The engine owns the machinery and the model-facing language it enforces: composed action descriptions, per-gate reply contracts, the spliceable turn-protocol prompt fragment, and engine-rendered read-backs and standing asks the model speaks verbatim. Mechanisms are configuration, not prompt prose — confirmation propose/execute gates with attempt budgets and stored-byte repetition, OTP and double-entry match gates, multi-turn flows, paginated reads, escalation ladders that count the prompt's "once" rules and escalate themselves, capture-bounce bounds, an engine-enforced abort policy, typed handoff routes, and a state-resolved handback envelope with orchestrator/specialized agent roles plus off-topic delegation. Graph state is one Zod schema (reducers + invoke-boundary validation, channel-completeness enforced at construction). Also: caller-capture param primitives, the twelve measured host-architecture design principles, porting an existing project onto agent-step, Kafka run-tracing observability via the companion kafka-observability plugin, the three-layer test methodology (runner unit / sandbox / prompt-input), and a channel-middleware contract audit.
4 skills
LangSmith-parity observability over Kafka for any LangGraph.js / LangChain.js agent: /add-kafka-observability installs or upgrades a vendored src/observability/ library that attaches a BaseTracer subclass globally through two redundant paths — the configure hook plus the configure-slot LangSmith's own tracer occupies, so it attaches even on platform runtimes that sever async-context ancestry (one startup() call, zero per-node instrumentation) — and publishes EVERY traced run — graph invocation, LangGraph nodes, LLM calls with full prompts/outputs/token usage, tool runs, errors, trace hierarchy, plus opt-in backend HTTP call runs via the traceBackendCall helper — as start/end events to a Kafka topic (standard envelope keyed by event id, thread_id correlation, zod-validated, secret-redacted, 512KB-truncated) over a bounded non-blocking fire-and-forget producer (librdkafka, acks=all, idempotent, bounded shutdown). By default EVERY run is emitted (full LangSmith parity); apps that have payload-verified which of their runs duplicate root/llm/tool content can opt into run filtering (KAFKA_RUN_FILTER_MODE=allow|deny + run_type:name globs, the name side also matching metadata.langgraph_node; the root run always survives — it carries the full invocation input/final state and is the turn-boundary marker for timeline consumers). Disabled by default (KAFKA_ENABLED); runs alongside LangSmith for parallel validation so LangSmith can be unplugged with no code change. Conversation content (prompts, completions, graph state, tool params) is masked by a policy the APPLICATION supplies — startup({ contentMask }) plus digit/deep-walk primitives that compose with a domain masker the project already owns, covering both numeral runs and digits SPOKEN as words (Greek + English packs, inflection/accent-tolerant — how PINs and OTPs actually arrive on a voice channel); the library ships the SEAM, not the policy (which digits are a tax id and which an order reference is a fact about the app's
1 skill