How do you stay aware of what your AI coding agents are doing?
I've been running Claude Code, Cursor, and Codex pretty heavily for the last few months and I keep hitting the same loop:
1. Start a task in one agent
2. Switch to something else (Slack, Twitter, another terminal)
3. Come back 30-40 minutes later
4. Agent finished 35 minutes ago. Or worse, it's been waiting for my approval the entire time.
The more agents I run, the worse it gets. There's no unified way to know what's happening across them.
Curious what other people's setups look like:
- Do you just keep terminals visible and check manually?
- Built any custom notification scripts?
- Use something like ntfy or Pushover?
- Just... accept the wasted time?
I've been building something in this space (push notifications + approval flows for AI agents) and I'm trying to understand if everyone's workflow is as janky as mine, or if some of you have figured out something clever.
Would love to hear what's working and what's not.


Replies
This is a very real problem.
Once you start using multiple agents, the bottleneck is not the code anymore. It is knowing what is running, what is stuck, and where your approval is needed. AI makes execution faster, but without a workflow around it, you just create new invisible waiting rooms.
Pushary
@nipuntaneja
"New invisible waiting rooms" is a great phrase, and it names the trap precisely: AI didn't remove the waiting, it moved it somewhere you can't see. Speeding up execution just relocated the bottleneck from the code to the coordination, and coordination delay is worse than slow code, because slow code is visible, you know it's grinding, whereas an agent parked waiting for approval looks exactly like an agent working. The waiting rooms are invisible because a stalled agent and a busy one are byte-identical from the outside.
And your first line is the real shift: once you're running multiple agents, the code stops being the hard part. Generation got cheap, so the scarce resource became knowing the state, what's running, what's stuck, where you're needed. That's not a coding problem, it's an awareness problem, and it's exactly the thing no faster model fixes, because a smarter agent that still can't tell you it's blocked leaves you in the same waiting room.
The workflow you're gesturing at is the fix, and the shape that matters is push over pull: you shouldn't have to go check which room has someone waiting, the room should announce itself. Otherwise "knowing the state" is just another polling loop you run manually, which caps out around three agents.
Curious, of your three, what's running / what's stuck / where I'm needed, which one actually costs you the most day to day? My hunch is "where I'm needed," since that's the one silently burning time while you assume it's still working, but you clearly feel this live and I'd rather hear which room bites hardest.
I stopped trying to watch everything it does. Instead I keep a pile of audit scripts that check decisions I've already made, and I run them after every change. If the agent quietly undoes something from three weeks ago, a script fails and I know right away. E2E tests cover the critical flows on top of that.
Watching the agent work is the easy part. Remembering what past me decided, and making sure the agent still respects it, turned out to be the actual job.
Pushary
@henry_s_jung
top notch! this is the best flow so far, but something that manages this saves me loads of time. Pushary by default, stores all your permission decision tree encrypted, and get weekly digests of your permissions audit report + pushary auto mode classifier automatically learns your behavior and unblocks your agent faster when it is obvious what decision you would take to the classifer.
no sales pitch but happy that there's someone else following this workflow.
Be awesome!
@aadilghani Appreciate it! The weekly permissions digest is a smart touch, decision fatigue is real. Good luck with Pushary!
With claude code - /remote_control in session and approve prompts on the go in the mobile app. It's also possible to do some automation with hooks, like maybe turning on alarm when task is done :) I haven't been using github copilot for a while, but I think I saw similar feature being introduced in "what's new" somewhere.
Pushary
@aiodintsov
The Claude Code /remote_control plus mobile-approve is a real chunk of the problem solved, and it's worth naming what it actually gets you: it kills the "tethered to the desk" part. Being able to approve from your phone means a blocked agent doesn't have to wait for you to physically be there, which is genuinely the away-from-keyboard half. And the hooks-for-alarms idea is the right instinct, wiring the Stop hook to something that reaches you is exactly how you stop polling.
The two gaps it leaves, and you half-flagged one yourself: it's per-tool. /remote_control solves it inside Claude Code, and you're already noticing Copilot has its own version, and that's the pattern, every tool ships its own island. So if you run more than one, you're back to a different remote-control surface per tool with no shared view, which is fine at one tool and messy the moment you're juggling Claude Code plus Codex plus something else.
The subtler gap: mobile-approve handles the approval cleanly, but approving from the phone works best for the trivial yes/no stuff. The moment the decision needs you to actually look at a diff, a button in the app isn't enough context to decide responsibly, so you're back at the terminal anyway. Which is fine, the trick is the alert telling you which kind it is so you don't approve a real change blind.
Curious, when you approve from the mobile app, is it mostly quick yes/no calls you're comfortable clearing on the go, or do you ever hit one where you wish you'd waited to see the actual change first? That line is the thing I keep chewing on.
Dial
the Cursor-is-a-black-box thread is the interesting part to me. instead of hooking into each tool's internal signal, what about going one layer lower and reading the OS process state directly, is the process blocked on a read() syscall (waiting for input, whether that's stdin or an Electron IPC channel under the hood) versus actively burning CPU. strace/ptrace-style monitoring is ugly and platform-specific but it doesn't care whether the tool is Claude Code, Cursor, or something that ships next month with zero hooks at all. feels like it trades "clean per-tool integration" for "one messier universal signal that never needs a new adapter." has anyone tried going that low level, or does it fall apart in practice once you actually attempt it
Pushary
@galdayan
Going lower is the right instinct, if the tool won't tell you its state, stop asking it and watch the process it can't hide. And the appeal is real: a `read()` on stdin looks the same whether it's Claude Code today or something with zero hooks next month. One signal, no adapters. That's the dream.
Where it bites in practice, three things. First, "blocked on read()" is noisier than it sounds, a modern app always has some thread parked on a read (UI events, sockets, watchers), so the condition is almost always true and tells you little. You still have to know which read matters, which is per-app knowledge again. Second, your Electron case is the sharp one: the approval-wait is an internal IPC event, so technically it's a blocked read, but telling "waiting for the user to click approve" apart from "Electron just idling" needs to know what that channel means, app-specific, the exact thing you were trying to avoid. Third, the practical killer: ptrace/strace is heavyweight, trips security tooling, fights SIP on macOS, needs elevated permissions. Asking a dev to run their agent under a tracer generates support tickets in the wild even when it works on your machine.
So it doesn't fall apart, it just doesn't deliver the clean universality it promises. You trade "one adapter per tool" for "one messy collector plus per-tool interpretation of what the syscalls mean", and the interpretation was the hard part all along. The per-tool knowledge is conserved; you can only move it around the stack.
Where it genuinely wins is as a fallback, not the primary: native hooks where they exist, process-level observation only for the zero-hook tools where it's "messy signal or nothing." For Cursor that might be the least-bad option, precisely because the clean alternative needs Cursor's cooperation and we don't have it.
Real question back, since you think at this level: have you found a way to pick out which blocked read is the meaningful one without app-specific knowledge? Because that's the crux, and if you've cracked it the whole thing gets a lot more universal. If you haven't, that's exactly where it turns back into an adapter.
Dial
one failure mode I haven't seen raised in this thread: the scary case isn't just one agent stalling, it's two agents about to collide - both about to touch the same file in a shared repo, or both about to burn through the same third-party rate limit at once. a push notification tells you after the fact that something already happened, it doesn't warn you before two runs step on each other. is cross-agent conflict detection on the roadmap at all, or is Pushary scoped to per-agent state changes rather than the interactions between agents?
Pushary
@galdayan
Straight answer: today Pushary is scoped to per-agent state, and you've correctly identified that cross-agent conflict is a different axis, not just more of the same. Per-agent notification is vertical, each agent reporting its own state up to you. Conflict detection is horizontal, the interactions between agents, and you can't derive the horizontal from stacking up the verticals, because two agents can each be in a perfectly healthy state and the combination is the problem. Each one individually reports "running, all good," and the collision lives in the space between them that no single agent's state describes.
And your two examples are actually two different hard problems wearing one label, worth splitting. The shared-file collision is detectable in principle before the fact, because there's a declarable resource, if you know each agent's intended write set (worktree, target files, the declared task path idea that came up earlier in this thread), you can see two claims overlap before either commits. That's a lock-manager-shaped problem: agents announce intent, the layer spots the overlap, warns or serializes them. Hard but tractable, and it's genuinely a before signal, not an after one.
The rate-limit collision is nastier, because the shared resource is external and invisible to the agents. Neither agent knows the other exists, neither knows the combined draw on the third-party limit, and the limit lives in someone else's system you can't inspect. So you can't detect the overlap by reading intent the way you can with files, you'd have to model the shared external resource yourself, track aggregate consumption across agents, and predict the collision. That's a real coordination layer, not a notification, and it's a meaningfully bigger thing to build.
Which is the honest scoping answer: conflict detection isn't an incremental feature on top of per-agent state, it's a second product surface, agents stop being independent things you observe and become a system you coordinate, with shared resources as first-class objects. It's squarely the direction this goes at scale (the "AgentOps" framing someone raised earlier is exactly this, the failure that matters isn't in any one agent, it's in the edges between them), but I'd be lying if I called it near-term. Per-agent state is the wedge because it's the acute pain today; cross-agent coordination is where it has to go once people are running enough agents that collisions stop being rare.
Genuine question, since you've clearly hit this: which of your two actually bites more in practice? Because the file-collision I think I can see a path to via declared write-sets, but the rate-limit one is the one I don't have a clean answer for, and if that's the one that actually costs you, it changes what's worth building first. My hunch is the silent rate-limit exhaustion is rarer but brutal when it happens, while file collisions are more frequent but you catch most of them at merge, curious whether that matches your experience or whether one of them is quietly costing you more than I'd guess.
Dial
@aadilghani that's a genuinely useful split, thanks for taking the question seriously. to answer directly - the rate-limit one has bitten harder for me, and precisely because it's invisible the way you describe. file collisions get caught fast, usually the moment you glance at a diff or run a merge, so the pain is real but short. the shared-limit case tends to surface as a vague "something felt off" hours later, degraded output or a stalled job you assumed was just thinking, and by the time you trace it back to exhausted quota you've lost the actual debugging thread of what you were doing. so agreed on the roadmap ordering - the wedge should be per-agent state now, but the invisible one is the sneakier tax long term.
Pushary
@galdayan
"Vague something felt off hours later" is the signature of the worst class of bug, and it's exactly why the rate-limit case is the sneakier tax. File collisions are honest, they fail loudly and near the point of impact, so the pain is sharp but short. The shared-limit case launders its own cause: the failure surfaces far from where it started, disguised as degraded output or a stalled job you assumed was thinking, so the expensive part isn't the exhausted quota, it's the debugging thread you lose reconstructing why. Delay plus disguise is what makes it costly, not the collision itself.
And that's the tell that it needs a genuinely different mechanism, because you can't catch it after the fact from state, by then the trail's cold. The only useful version is predictive, model the shared external resource and see the combined draw approaching the limit before it hits, which is real coordination, not a notification. So agreed on the ordering for the right reason: per-agent state is the wedge because it's the acute, visible pain, and the invisible one is the long-term tax precisely because nothing today even surfaces it until it's already cost you.
Good exchange, this is one I'm carrying into how I think about the roadmap's second phase. Appreciate you pushing on the horizontal axis, it's the part that's easy to under-weight when the vertical pain is louder.
Dial
@aadilghani good place to leave it, and I appreciate you actually taking the horizontal axis seriously instead of nodding at it and moving on. one last thing before I let this go - the "model the shared external resource" idea, is that something Pushary would build by having each agent self-report its estimated cost before a call, or would it watch actual response headers/usage centrally and infer the combined draw without needing the agents to cooperate at all. self-reporting seems like it'd break exactly when you need it most, which is a misbehaving agent
Yep this is a real pain. Once you start using more than one coding agent it gets messy really fast. I still don't have a good solution, just lots of terminal tabs and hoping I don't miss anything 😂
Push notifications for approvals/completed tasks actually makes a lot of sense. Curious how you handle different agents tho.
Pushary
@pagesv
"Lots of terminal tabs and hoping I don't miss anything" is the honest baseline, and the 😂 stops being funny right around the third agent. Tabs plus hope is a polling loop where you're the CPU, and hope means you're just accepting you'll miss some. Which is the part that costs you.
How I handle different agents: a thin adapter per tool that catches each one's native signal and normalizes it into one state model. Codex has a native approval event, Claude Code gives clean hooks, Cursor's the stubborn one. The adapter eats each tool's weirdness so you get one inbox that knows all of them, instead of one habit per terminal.
It's free to try, so honestly just point it at your setup and see, pushary.com. You're exactly who it's built for.
One thing while you're there: is it agents finishing you miss, or agents blocked waiting? The blocked ones are the silent killers, burning time while you assume they're working, so that's the one I'd make loudest.
Dial
I run a handful of sessions in a terminal multiplexer and just alt-tab through panes manually, which is exactly the janky workflow you're describing. tried a shell hook that pings Slack when a session goes idle, worked fine for one agent but got noisy fast once I had 4-5 running, couldn't tell which ping actually needed me versus which one was just "done, no action needed". if push notifications + approval flows is the space you're building in, the thing I'd want most is filtering by urgency, not just "agent stopped" but "agent stopped AND is blocked waiting on you" vs "agent stopped and finished cleanly"
Pushary
@omri_ben_shoham1
You've hit the exact wall the hook-plus-Slack approach always hits, and it's worth naming why: your hook fires on idle, but idle is one signal collapsing two completely different states. Done-cleanly and blocked-waiting-on-you both look like "the session went quiet," so your pings were structurally unable to tell you which one they meant. Not a tuning problem, an information problem, you were alerting on the absence of activity, and absence can't distinguish between "finished" and "stuck." At one agent you could just check. At 4-5 the ambiguity multiplies and the channel becomes noise, so you mute it, and now you're back to alt-tabbing.
And that's exactly the split you're asking for and the right one: those two aren't different urgencies of the same event, they're different events. Finished-cleanly is informational, nothing's waiting, the cost is fixed, read it whenever. Blocked-waiting-on-you is a live stall, the agent is frozen and the meter's running, and every minute you don't know costs you. One's a receipt, one's a bill that's still accruing. They shouldn't even sound the same on your phone.
The catch, and the reason your hook couldn't do it: getting that split reliably means the agent has to declare "I'm blocked" as a distinct event, not go quiet and let you infer. That's native hooks, Codex exposes a real approval event, Claude Code gives clean signals on shell and file edits, so you can catch the actual block rather than guessing at silence. That's what makes the urgency filter possible instead of just aspirational, and it's exactly what I'm building: blocked pings loudly, done goes in a list you glance at, everything else stays dark.
Free to try if you want to point it at your multiplexer setup, pushary.com, and you're the ideal test case since 4-5 agents is precisely where the hook approach dies. Curious though, in your Slack pings, what was the actual ratio, mostly "done, no action needed" with the occasional real block? Because if the blocks were rare, the noise was almost entirely the done-pings, which suggests done probably shouldn't push at all.
haha i can relate
Pushary
@raza_mughal1
one hundred percent
You named the real tax, which is not the waiting itself but the constant context switching just to check whether the wait is even necessary. The two states are worth treating very differently. "Done and idle" is a notification problem, but "stuck waiting on approval" is closer to an interrupt, since every minute there is pure dead time. I would make those two feel different the moment they reach you: a soft nudge for completion, and something much harder to ignore for a blocked approval, so you can triage without opening a terminal. The parallel part is where it gets hard. Past two or three agents, people stop wanting per agent pings and start wanting one glanceable place that answers who needs me right now. Sounds like you are already headed there. How are you thinking about which approvals can be safely auto granted versus the ones that always need a human?
Pushary
@asadmalik901
Direct answer: the gate keys on recoverable cost of error, roughly blast radius × (1 − recoverability), not on reversibility alone. Reversibility is the cheap first approximation and it fails both ways. It over-fires on irreversible-but-trivial (the agent logs a timestamp, can't undo it, nobody cares) and under-fires on reversible-but-catastrophic (mass email to 50k users, you can send a correction, the damage already landed). So what earns a human is unrecoverable damage, not whether an undo technically exists.
The wrinkle is that the agent can't compute its own blast radius. It doesn't know 50k people are on that list. Reach is the one variable it's structurally worst at estimating about itself, so in Pushary reach gets annotated at the tool and resource layer rather than inferred by the agent, and human judgment stays reserved for genuinely novel reach. Cheap, reversible, low-reach auto-clears, and that's most of the volume.
The part I care most about getting right: auto-grant should only ever loosen with evidence, never because you clicked yes quickly a few times. Fast approval on a trivial action means trust. Fast approval on a risky one might just mean you weren't looking. Conflate those and the system quietly learns to rubber-stamp on your behalf, which is worse than no automation at all.
And yes on your interrupt distinction, that's exactly how it's built: blocked is loud and answerable from your phone, done drops into the glanceable list. You put it better than my landing page does, done is a receipt, blocked is a bill that's still running.
MonoCloud for Startups
The fix that worked for me was structural, not more discipline. Agents write to a branch, every run ends with a short summary of what changed and which files it touched, and I review that like any other diff instead of tailing logs. Real-time supervision does not scale past one agent, and you are running three. Make them report to you asynchronously and the anxiety mostly goes away.
Pushary
@shivangit26
"Structural, not more discipline" is the right diagnosis, because discipline is a strategy that fails quietly at exactly the moment you're busy, which is always. You didn't try harder to watch, you changed the shape of the problem so watching wasn't required. That's the difference between a fix and a resolution.
And the specific structural move is the good one: branch plus an end-of-run summary of what changed and which files it touched means you review a diff instead of tailing a log. Those are wildly different costs. A log is the agent's stream of thought, so reading it means re-deriving what happened. A diff plus summary is effects-first, so you're reading conclusions. Same information, a fraction of the attention, which is why the anxiety drops, you're not holding six live sessions in your head, you're reviewing artifacts on your schedule.
The one gap async-reporting leaves, and it's the thing I'm building around: it handles done beautifully and can't help with blocked. If an agent stalls mid-run waiting on an approval, the end-of-run summary never fires, because there's no end of run. So the failure mode isn't the finish you'll review calmly later, it's the agent that's been frozen for 20 minutes while you assume it's still working. Async reporting fixes the review cost; it doesn't surface the silent wait.
Curious, with agents on their own branches, do you hit approval stalls often, or have you pre-authorized enough that they mostly run clean to the summary? Because if they rarely stop to ask, you've genuinely solved this and a notification layer would just be noise on top.