railtownai/railtracks/agent-builder
Claude Code and agent skill by railtownai/railtracks
- community
Checking that the SKILL.md file is still in the repository.
Build an agent using the railtracks Python framework. Use when the user wants to create an AI agent, tool-calling workflow, or multi-agent system with railtracks.
Install
npx vskill@latest install railtownai/railtracks/agent-builderSKILL.md
Build a Railtracks Agent
The user wants to build an agent using the railtracks framework: $ARGUMENTS
How railtracks works
- Tools are plain Python functions decorated with
@rt.function_node. Type hints become the parameter schema; the docstring becomes the description. - Agents are created with
rt.agent_node(). Its behaviour depends on whether tools or a structured output schema are passed (see below). - Flows wrap an agent or async function as the entry point and handle execution, config, and context.
- `rt.call()` is used inside async workflows to call agents or nodes directly.
- Results:
flow.invoke(),await flow.ainvoke()andawait rt.call()on an agent return a response object. Read it with.content: astrfor a text agent, an instance of your schema for anoutput_schemaagent. The full conversation is on.message_history. When the agent was given anoutput_schema,.structuredalso returns that instance; otherwise.textalso returns thestr.
What agent_node builds
rt.agent_node() builds one node behind the scenes — there is no separate named type to pick. What you pass changes what the agent does at runtime:
| Passed | Behaviour | |
|---|---|---|
Neither tool_nodes nor output_schema | Plain chat, text output | |
output_schema only | Structured output, no tools | |
tool_nodes only | Tool-calling loop, text output |
LLM Providers
Steps
- Read the existing code — check what files already exist in the project. Understand the task before writing anything.
- Identify what tools the agent needs — each capability the agent should have becomes a
@rt.function_node. Ask the user to clarify if it's not obvious from$ARGUMENTS. - Define the tools — write each tool as a Python function with:
- Full type hints on all parameters and return value
- A docstring with a one-line summary and
Args:/Returns:sections - Real implementation (or a clear stub with a TODO if the user needs to fill it in)
- Define the agent — call
rt.agent_node()with (note: it returns a class/type, so use PascalCase for the variable name):
- A descriptive name
tool_nodeslisting the tools (if any), oroutput_schemaas a PydanticBaseModelfor structured output — one or the other, never both (passing both raisesNodeCreationError)llm— follow the provider the project already uses, or one whose API key is configured (providers and their key variables: https://docs.railtracks.org/documentation/getting_started/llm_setup/); otherwise ask the user which LLM to usesystem_message— a clear, specific system prompt
- Wrap in a Flow — create
rt.Flow(name="...", entry_point=MyAgent)for simple cases. For multi-step or multi-agent workflows, define anasync deffunction as the entry point and useawait rt.call(MyAgent, ...)inside it. - Add invocation code — include a
if __name__ == "__main__":block that callsflow.invoke(...)with a representative example and printsresult.content, so the user can run it immediately. Useawait flow.ainvoke(...)instead if the code is already async. - Check imports — make sure
import railtracks as rtis at the top and any Pydantic models importfrom pydantic import BaseModel.
Patterns to Follow
Simple Agent with Tools
Structured Output
Decision Node (Classify, Route, Grade)
When the output is a judgment you act on in code (yes/no, one of a fixed set of labels, a level on a rubric), use rt.decision_node with a decision model instead of an LLM. One request answers every question with calibrated probabilities. Input is text, or a JSON object or array; no images.
It's also a tool: pass it in an agent's tool_nodes. Failures raise rt.exceptions.DecisionModelError. Only node middleware (rt.wrap_node, rt.post_node) works; model middleware such as pre_llm raises NodeCreationError. Docs: https://docs.railtracks.org/documentation/agent_design/decision_nodes/
Multi-Agent Workflow
Async Invocation
Use flow.invoke() from sync code and await flow.ainvoke() from async code.
Streaming
rt.astream streams an agent's text as it's generated. It's async only; there is no stream=True on models.
await rt.astream(...) without the loop returns just the final response.
Agent Used as a Tool by Another Agent (Multi-Agent Orchestration)
An agent with a system_message can be passed straight into another agent's tool_nodes. Without a manifest=, railtracks names the tool after the agent (characters outside [a-zA-Z0-9_-] become _), builds the description from the agent's name and full system message, and gives it one required string parameter, request, which the sub-agent receives as its user message. An agent with neither system_message nor manifest= raises NodeCreationError when used as a tool. {placeholders} in the system message are never filled in the description, because ContextInjection fills messages only; pass a manifest when the sub-agent's system message is templated.
Pass rt.ToolManifest to agent_node when the caller needs a shorter description than the system message, named parameters, or a description that does not reveal the prompt. A manifest without parameters keeps its description and takes request. A manifest with a blank description raises NodeCreationError.
Parameter fields:
name— the argument name the orchestrator LLM passesdescription— explains what to put in this argumentparam_type— JSON schema type string ("string","integer","number","boolean", …) or a Python builtin mapped the same way:str,int,float(→"number"),bool,list/tuple/set(→"array"),dict(→"object"),type(None)(→"null"). Unknown types fall back to"object".required— defaults toTrueenum— optional list of allowed values
MCP Tools
Visualizing Runs
Every run is recorded to .railtracks/ automatically, no code needed. To inspect runs in the local visualizer, have the user run these from the project root:
railtracks viz --beta downloads the beta UI on first use and serves it at http://localhost:3031. It blocks, so don't start it from inside the agent script.
Rules
- Pass
llm=to everyrt.agent_node(...); it's required. - Add guardrails with
@rt.input_guard/@rt.output_guardinmodel_middleware=[...]. - Import prebuilt guards (
BlockTextInputGuard,PIIRedactConfig,ScopeGuard, …) fromrailtracks.prebuilt.guardrails. - Stream with
rt.astream(...). - Run agents through
rt.Flow(...). - Give each agent one entry point: a
Flow, orawait rt.call()inside another node. - Write each tool's docstring as a clear, specific description; it's the tool description the LLM sees.
- Type-hint every tool parameter and return value; the hints define the tool's parameter schema.
- Give each agent only the tools it needs.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingpackages/railtracks/src/railtracks/cli/skills/agent-builder/SKILL.md
Popularity
- Repository stars
- 235
- Repository forks
- 67
- 7-day trend score
- 5
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/railtownai/railtracks/agent-builder)