VibeSignal explores a simple interaction problem that becomes increasingly important when working with multiple AI agents:
How do I know when an agent actually needs me without constantly watching the terminal?
Instead of adding another notification stream, VibeSignal translates agent state into a small set of peripheral visual signals.
A physical USB light on the desk, an onscreen widget, or a terminal panel can communicate whether an agent is:
- working
- waiting for human input
- finished
- in an error state
The goal is not to show everything an agent is doing.
The goal is to make human attention visible.
Traditional software mostly waits for the user.
Agentic software does something different.
A person can start a task, shift attention elsewhere, and return later when the system needs a decision, permission, clarification, or review.
That creates a new UX problem:
Human starts task
↓
Agent works independently
↓
?
↓
When does the human need to return?
When several agents are running simultaneously, watching each terminal defeats much of the value of delegation.
Desktop notifications help, but they create their own problems:
- they compete with other notifications
- they disappear
- they often communicate activity rather than urgency
- they require looking back at the screen
VibeSignal experiments with a different model:
use peripheral awareness to communicate when human attention becomes necessary.
The initial hypothesis was:
An AI agent should communicate changes in the human-agent relationship, not every change in its internal activity.
That led to a small state vocabulary.
| State | Signal | Meaning |
|---|---|---|
| Working | Blue | The agent is progressing. No action needed. |
| Blocked | Amber | The agent needs human input or permission. |
| Done | Green | The agent has completed its turn. |
| Error | Red | Something failed and may require attention. |
| Idle | Off | Nothing currently needs attention. |
The physical light is intentionally low-information.
You should be able to understand the state from across the room without reading anything.
The main renderer is a USB status light sitting on the desk.
AI agent
↓
Agent events
↓
VibeSignal state
↓
┌──────────────┐
│ DESK LIGHT │
└──────────────┘
↓
peripheral awareness
The user does not need to keep a terminal visible.
If the light is blue, keep doing what you're doing.
If it turns amber, an agent needs you.
If it turns green, the agent has finished its turn.
The interaction is intentionally closer to a traffic signal than a dashboard.
One of the more interesting parts of building VibeSignal was discovering that the events exposed by AI tools do not always map cleanly to what a person believes the agent is doing.
An event might technically mean that something stopped.
That does not necessarily mean:
the task is finished.
Likewise, an inactivity event might appear to mean:
the agent is waiting for me.
In practice, it may simply mean the model is between visible actions.
Those distinctions matter because the interface is making a promise about attention.
An amber signal means:
You are needed now.
If amber fires when no action is actually required, the signal quickly loses credibility.
The project began as a fork of yzhao062/vibesignal.
Using the light during real AI-assisted development exposed several cases where the upstream event mappings did not match the user's mental model.
A Claude Code turn can stop because the agent has completed its work.
It can also stop because the agent asked a question or entered a state that requires human input.
Treating both situations as done produced a green light even when the agent was waiting for me.
VibeSignal now checks the end of the agent transcript.
If the turn ended with something such as:
AskUserQuestion
ExitPlanMode
the state becomes:
BLOCKED
rather than:
DONE
The implementation changed because the interaction semantics were wrong.
An earlier version treated Claude Code's idle_prompt notification as a signal that the agent needed attention.
Actual use showed that this event can also appear during ordinary reasoning or composition gaps.
That produced false amber signals.
The mapping changed from:
idle_prompt → blocked
to:
idle_prompt → working
Amber is now reserved for states where human intervention is actually required.
This is a small technical change with an important UX consequence:
the system becomes more trustworthy by signaling less.
When several AI sessions are active, their states can conflict.
One agent may be working while another needs permission.
VibeSignal resolves them using an attention hierarchy:
blocked
↓
error
↓
working
↓
done
↓
idle
If even one agent needs the human, the light becomes amber.
This means a lower-priority state can never hide the signal that matters most.
The design question is not:
Which agent changed most recently?
It is:
Which state most requires human attention?
A single signal cannot answer every question, so VibeSignal uses progressive disclosure.
For peripheral awareness.
Answers:
Do I need to pay attention?
For lightweight identification.
Answers:
Which agent needs me?
For detailed session state.
Answers:
What is happening across all active agents?
Physical light
↓
Is attention needed?
Floating widget
↓
Which agent?
Terminal panel
↓
What is each session doing?
Each interface provides only the level of detail appropriate to its context.
VibeSignal tracks Claude Code and Codex sessions through the same state system.
Each active session records:
- agent
- project
- session
- current state
- time of last meaningful event
The aggregate signal is calculated across all sessions.
This makes it possible to run several agents simultaneously while maintaining a single peripheral answer to the most important question:
Does anything need me right now?
VibeSignal currently supports three representations of the same underlying state.
| Renderer | Purpose |
|---|---|
| USB busylight | Peripheral awareness away from the screen |
| Floating widget | Persistent lightweight session visibility |
| Terminal watch panel | Detailed multi-session monitoring |
All three read the same state store.
That lets the interaction move between glanceable and detailed without introducing different meanings for the states.
| State | Physical signal | Meaning |
|---|---|---|
blocked |
Amber | Human action required |
error |
Red | Failure requiring inspection |
working |
Blue | Agent actively progressing |
done |
Green | Agent completed its current turn |
idle |
Off | No active attention requirement |
Aggregate priority:
blocked > error > working > done > idle
The exact color is less important than the semantic distinction between:
Needs me
Does not need me
Agent hooks send state changes to VibeSignal.
flowchart LR
A["Claude Code / Codex"] --> B["Agent hooks"]
B --> C["VibeSignal state"]
C --> D["USB light"]
C --> E["Floating widget"]
C --> F["Terminal panel"]
Each session writes its state independently.
VibeSignal then resolves the highest-priority active state and updates the renderers.
The architecture is deliberately lightweight:
- no long-running daemon is required for hook processing
- session records are written atomically
- concurrent agents share a common state store
- stale sessions expire automatically
- blocked states persist long enough to remain visible
This repository began as a personal fork of yzhao062/vibesignal.
The upstream project provided the core architecture and USB light integration.
My changes focus primarily on adapting it to my own AI-assisted design and development workflow and refining the interaction semantics based on actual use.
In particular:
- distinguishing a genuinely completed turn from a turn that stopped to ask the user something
- reducing false "needs attention" signals
- supporting concurrent Claude Code and Codex sessions
- treating the physical light as an attention interface rather than simply a process-status indicator
This repository is maintained primarily as a working personal tool rather than a general-purpose distribution.
For the upstream installation instructions and broader cross-platform support, see:
For this fork, the basic workflow is:
pip install -e .Configure Claude Code hooks:
vibesignal install-hooksOr Codex:
vibesignal install-hooks --agent codexVerify current sessions and resolved state:
vibesignal statusLaunch the onscreen widget:
vibesignal widgetOr view sessions in the terminal:
vibesignal watchVibeSignal is a small project, but it points toward a larger design problem.
As software becomes increasingly autonomous, interfaces will need to communicate more than system status.
They will need to communicate the changing division of responsibility between the person and the machine.
At any moment:
Who is acting?
Who is waiting?
Who has control?
Who needs whom?
Traditional UI patterns were largely designed for software that waits for commands.
Agentic products create long periods where the software acts independently and the user becomes the exception handler, reviewer, collaborator, or decision-maker.
That changes the role of attention in interface design.
VibeSignal is one experiment in what that relationship might look like.
This project is part of a broader design practice in which I use working software to explore emerging interaction models.
The interesting question is not simply whether an interface can be built.
It is whether the underlying system behavior creates an understandable, trustworthy relationship with the person using it.
Here, that meant moving from:
show me what the AI is doing
to:
tell me when the AI needs me.
That distinction is the product.