@alexeino/wow
v0.1.0
Published
Team operating principles + Telegram-based Architect escalation for Claude Code, via per-developer bots.
Maintainers
Readme
@alexeino/wow
Team operating principles + a Telegram-based Architect escalation system, packaged as one dev dependency for Claude Code projects.
Installing this package does two things for a project:
- Writes a set of feature-slicing rules into
CLAUDE.md, so any Claude Code session in the project follows the team's workflow automatically. - Gives Claude Code two CLI commands to escalate high-risk decisions to the Architect over Telegram, and to check for the Architect's reply.
Install
npm install --save-dev @alexeino/wow
npx @alexeino/wow initnpm install alone just prints a reminder to run init — the actual setup (prompting for credentials, writing files) always happens in the explicit init command, so it behaves the same whether you're installing locally, in CI, or with --ignore-scripts / pnpm (which skips postinstall scripts by default).
Self-service onboarding (per developer, once)
Each developer gets their own dedicated Telegram bot — not a shared team bot. This is deliberate: a shared bot would require reply-threading and offset-matching logic to keep different developers' escalations from colliding in one update queue. A per-developer bot sidesteps that entirely — each bot's update queue is private to it, so "check for the Architect's reply" can simply mean "the latest message on this bot."
The trade-off: the Architect sees a separate Telegram chat per developer instead of one inbox. For a small team, that's a much smaller cost than the added complexity of shared-queue threading.
End-to-end flow:
- Developer creates their own bot via @BotFather on Telegram — message it, send
/newbot, pick a name and username. Takes about 2 minutes, no Architect involvement. - Developer runs
npx @alexeino/wow init, pastes their bot token and the team'sARCHITECT_CHAT_ID(see below).initvalidates the token, writes.env,.env.example, updates.gitignore, and generates/updatesCLAUDE.md. initprints a link to the new bot (https://t.me/<username>). The developer sends that link to the Architect.- The Architect opens the link and sends any message (e.g. "hi") to that bot. This is a Telegram platform requirement, not a design choice — a bot cannot message a user who hasn't started the conversation with it first. It's a ~10-second action, and it's the Architect's only manual step per new developer (no bot creation or token handling on their side).
- Escalations now work for that developer.
This scales to any team size — the Architect never creates or manages bots, they just send one starter message per new bot they're linked to.
Where ARCHITECT_CHAT_ID comes from
In a private Telegram chat, chat_id is tied to the Architect's own account, not to which bot is messaging them — so this value is the same for every developer's bot and never changes. The Architect finds it once (call getUpdates on any one bot after messaging it, and read message.chat.id from the response) and shares that single number with the whole team.
CLI commands
npx @alexeino/wow init
npx @alexeino/wow escalate --feature "<name>" --question "<question>" --options "<options considered>"
npx @alexeino/wow check-replyescalatesends a formatted message to the Architect via this developer's own bot (readingTELEGRAM_BOT_TOKENfrom.env). No--devflag is needed — the bot itself identifies who's escalating, since the Architect sees it arrive as a distinct chat.check-replycallsgetUpdateson this developer's own bot and prints every message the Architect has sent since the last check, in order — so a reply the Architect splits across a few Telegram messages isn't truncated to just the last fragment. If nothing new has arrived since the last check, it re-shows the last known message instead of going silent. Because each bot's queue is private to one developer, this needs no reply-threading or escalation-ID matching — just "what's new since I last looked," tracked in a small local.wow-checkreply-state.jsonfile (gitignored). It never marks messages as consumed on Telegram's side either, so nothing is ever lost even across a fresh clone/checkout.- If no message has ever arrived,
check-replysays so plainly instead of erroring.
Both commands read TELEGRAM_BOT_TOKEN and ARCHITECT_CHAT_ID from .env (or process.env) — never hardcoded, never logged.
Example usage inside a Claude Code session
Developer: Let's add a "delete account" button to settings.
Claude: This touches an irreversible action (account deletion) — it needs
Architect review before we proceed. Should I send this to the Architect?
Developer: yes
Claude: [runs] npx @alexeino/wow escalate \
--feature "Delete account button" \
--question "OK to add a self-serve delete-account button, or does this need a confirmation flow / grace period first?" \
--options "A) immediate delete B) 7-day soft-delete then purge"
Claude: Sent to the Architect. I'll hold off on implementing this until we
have a reply — you can ask me to check any time with check-reply.
Developer: check now
Claude: [runs] npx @alexeino/wow check-replyThe generated CLAUDE.md documents the fixed trigger categories and this stop-and-confirm behavior in full, so Claude Code picks it up automatically in any project with this package installed.
.env safety
initadds.env(and the local.wow-escalations.log) to.gitignoreif they aren't already ignored — credentials are never committed.- Only
.env.example(placeholders, no real values) is meant to be committed. - Credentials are read via
process.env/ a local file read and are never printed to stdout or written to any log, including the escalation log (which stores only feature/question/options/timestamp, not tokens or chat ids).
Local prototype testing (npm link)
# in this package's directory
npm link
# in a fresh, empty project
mkdir /tmp/wow-test && cd /tmp/wow-test
npm init -y
npm link @alexeino/wow
npx wow initPublishing
@alexeino/wow is a personal npm scope, not an organization — scoped packages default to private on publish, which requires a paid plan. This package is meant to be free and public, so it must be published explicitly with the public flag:
npm publish --access public(package.json also sets "publishConfig": { "access": "public" } as a backstop, but always pass the flag explicitly too.)
