# ThinkRail's Agent Skill System: How JetBrains Built Self-Extending IDE Capabilities Around Living Specs

> Source: <https://dev.to/mech_app_ai/thinkrails-agent-skill-system-how-jetbrains-built-self-extending-ide-capabilities-around-living-1co>
> Published: 2026-10-29 00:08:34+00:00

JetBrains shipped ThinkRail as an IDE where agents can write their own capabilities instead of waiting for plugin updates. The project hit 5,016 stars and #1 on GitHub Trending (TypeScript) by combining isolated workspaces, living specs as durable project knowledge, and a skill system that lets the pi coding agent extend itself based on how you actually work.

This is not a wrapper around an LLM chat interface. ThinkRail is a full IDE built around agent-extensibility as a core feature. The agent can create tools, register them as reusable skills, and invoke them across workspace boundaries without breaking existing state.

ThinkRail runs on three layers:

The pi coding agent sits at the center. It decides when to invoke an existing skill versus writing a new one based on the task context and available specs.

Each workspace is a separate git worktree. The agent can:

This prevents a newly-created skill from corrupting the main branch or interfering with other active workspaces. If a skill fails, the worktree is disposable. You lose the experiment, not the project.

Traditional documentation goes stale. Living specs are different:

When the agent needs to create a new skill, it queries the spec registry for relevant context. The spec provides:

This makes specs a **durable knowledge substrate** instead of a brittle reference. The agent does not hallucinate tool signatures because the spec includes the actual contract.

The skill registry is a lookup table mapping task patterns to executable capabilities. When the agent receives a request, it:

| Condition | Action | Rationale | 
|---|---|---|
| Exact skill match | Invoke existing skill | Reuse proven capability | 
| Partial match + simple delta | Compose existing skills | Avoid redundant code | 
| No match + spec exists | Generate new skill from spec | Leverage durable knowledge | 
| No match + no spec | Prompt user for clarification | Prevent hallucinated tools | 
| Skill fails in test | Rollback and log | Protect workspace state | 

The registry does not blindly invoke. It checks workspace compatibility first. A skill written for a Node.js project will not run in a Python workspace, even if the task description matches.

Here is how the agent creates a new skill:

```
// Simplified skill generation flow
async function generateSkill(intent: string, workspace: Workspace): Promise<Skill> {
  // 1. Query living specs for relevant context
  const specs = await specRegistry.query(intent);

  // 2. Generate skill code using spec patterns
  const skillCode = await agent.generate({
    intent,
    specs,
    workspace: workspace.context,
    constraints: workspace.securityBoundaries
  });

  // 3. Test in isolated worktree
  const testResult = await workspace.test(skillCode);

  if (!testResult.success) {
    throw new SkillGenerationError(testResult.errors);
  }

  // 4. Register skill with metadata
  const skill = {
    id: generateSkillId(intent),
    code: skillCode,
    metadata: {
      createdAt: Date.now(),
      workspace: workspace.id,
      specs: specs.map(s => s.id),
      testCoverage: testResult.coverage
    }
  };

  await skillRegistry.register(skill);
  return skill;
}
```

The key is step 3: testing in isolation. The agent does not register a skill until it passes tests in the worktree. This prevents broken tools from polluting the registry.

Agent-generated skills are powerful and risky. ThinkRail enforces three boundaries:

The agent cannot escalate privileges. If a skill needs network access, the user must update the spec to allow it. The agent can propose the change, but it cannot self-approve.

| Failure | Impact | Mitigation | 
|---|---|---|
| Skill generates invalid code | Test fails, skill not registered | Worktree rollback | 
| Skill passes tests but breaks in production | Workspace corruption | Git reset to pre-skill state | 
| Skill conflicts with existing skill | Registry collision | Namespace isolation by workspace ID | 
| Spec drift (code changes, spec does not) | Agent generates outdated skill | Spec validation on commit | 

The most dangerous failure is spec drift. If the spec says a function takes two arguments but the actual implementation takes three, the agent will generate a broken skill. ThinkRail mitigates this with pre-commit hooks that validate specs against the codebase.

ThinkRail is adding full extension support next. This means:

The extension API will expose:

This turns ThinkRail into a platform, not just an IDE. You can build domain-specific skill libraries (e.g., "Kubernetes deployment skills" or "React component generation skills") and share them across teams.

The agent logs every skill invocation with:

This creates an audit trail. If a skill breaks something, you can replay the invocation in a fresh worktree and debug it without affecting the main branch.

The logs also feed back into the skill registry. If a skill consistently fails for certain input patterns, the agent can flag it for review or automatically deprecate it.

ThinkRail runs as a desktop Electron app. The agent backend is a Node.js process that:

The frontend is a React app that renders:

All state lives locally. There is no cloud dependency for core functionality. You can use your own LLM API keys (OpenAI, Anthropic, local models via Ollama).

**Use ThinkRail when:**

**Avoid ThinkRail when:**

The skill registry is the breakthrough. Most agentic IDEs treat the agent as a code generator. ThinkRail treats it as a capability builder. The agent does not just write code for you. It writes tools for itself, tests them, and adds them to its own toolkit. That is a different kind of automation.
