← Back to logs

Why I Built Exciton

·5 min read·

Agentic frameworks for Claude Code install once and govern every session. A three-line bug fix shouldn't get the same ceremony as a new subsystem, so I built a per-session dial.

Agentic frameworks like superpowers make Claude Code dramatically better at big work. They push it to brainstorm first, write a plan, get approval, and work in small, reviewed steps.

For a new subsystem, that's exactly what I want.

For a three-line bug fix I've already diagnosed, it's a lot of ceremony.

It kept happening on the smallest tasks. I'd already read the stack trace, found the line, and knew the fix. All I wanted was the diff. Instead, the session opened with a brainstorm, asked clarifying questions about a change I'd already decided, and proposed writing a plan for my approval.

None of that was the framework misbehaving. It was doing exactly what it was built to do, on every task, because it had no way to know which tasks deserved it. After enough small fixes that took longer with the framework than without it, I stopped blaming the framework and started building the missing dial.

The Problem: Frameworks Are All or Nothing#

These frameworks install once, globally, and then govern every session. Claude Code plugins are enabled by default when installed, and there's no supported way to say "this session, keep the skills around but don't force the process."

Someone asked for exactly that in superpowers' issue #645: a mode that skips the automatic injection but keeps the skills callable. It was closed without being implemented.

So the choice was: live with the ceremony everywhere, or uninstall the framework and lose it for the work where it shines.

The Idea: A Per-Session Dial#

Exciton runs Claude Code with a framework set to the level the task deserves, for one session, without changing anything else:

npm i -g exciton

exciton superpowers --no-hooks   # skills stay callable, nothing auto-fires
exciton superpowers              # the full framework, exactly as published

Quit it, run plain claude, and everything behaves exactly as before.

The name comes from physics. An exciton is a bound electron–hole pair. It exists only while the system is excited, and when it recombines, the material is exactly as it was. That's the whole design goal: a configuration that lives for one session and leaves no trace.

How It Works Without Touching Your Setup#

Exciton uses two documented Claude Code features and nothing else:

  • --settings '{"enabledPlugins":{"<id>":false}}' turns a plugin off for one session.
  • --plugin-dir <dir> adds a plugin for one session from a directory you control.

For --no-hooks, Exciton stages a copy of the framework with its hooks/ directory left out. Hooks are discovered by convention, so removing the folder leaves nothing dangling. The skills are still there; nothing pushes them into the conversation.

The most important rule: nothing under ~/.claude is ever written. Exciton reads your Claude Code configuration and only writes inside ~/.exciton/. It never runs claude plugin install, because installing a plugin enables it globally, which is the exact problem it exists to avoid.

Decisions I Made on Purpose#

One framework at a time. Frameworks like superpowers, BMAD, and Spec Kit all define how a session is run, so two of them would fight over the same job. Naming two is refused. Ordinary plugins (language servers, MCP integrations, design helpers) just add capabilities, so Exciton never touches them.

No version picker. A framework is either the copy Claude Code already has, or Exciton's own copy of the newest release, refreshed with exciton update. Choosing between releases is a question almost nobody needs answered, and supporting it would have meant a @version syntax that collides with Claude Code's own name@marketplace plugin IDs.

Explain before acting. The first run walks you through what Exciton is and lets you add the frameworks you want. It doesn't assume you already agree with it.

Proof, not promises. An integration test suite checks real Claude Code behavior against its own debug output, including that no Claude state file is modified.

When I Reach for It#

My rule is simple: the amount of process should match the amount of uncertainty.

Plain claude for mechanical work: a dependency bump, a config change, a rename, or a question about the codebase. No framework at all.

exciton superpowers --no-hooks for work I've already figured out: a bug I've diagnosed, a small feature with an obvious shape, or a refactor I can describe in one sentence. The skills are still on the shelf, so if the task turns out bigger than I thought, I can ask for brainstorming or a plan by name. But nothing forces a design review on a three-line fix.

exciton superpowers when the uncertainty is real: a new subsystem, an unfamiliar codebase, or anything where getting the design wrong is expensive. That's where brainstorm, plan, approve, and small reviewed steps earn their cost.

The xc alias keeps all of this short, e.g. xc superpowers --no-hooks.

The biggest change isn't speed. It's that I stopped fighting the framework. Before, every session meant either sitting through the full process or uninstalling the framework and losing it for the work it's great at. Now that decision takes one flag at the start of the session, and it never follows me into the next one.

Try It#

npm i -g exciton
exciton

It needs Node 22.18 or newer, Claude Code on your PATH, and macOS or Linux. The source and the full mechanism write-up are on GitHub.