Skip to content

[BUG] core/safety.py writes the approval prompt to stdout from a library path #595

Description

@SakethSumanBathini

Problem

agentwatch/core/safety.py renders the human-approval prompt with 13 direct print() calls
(around L889):

print("\n" + "=" * 60)
print("⚠️  AGENTWATCH SAFETY CHECK")
print("=" * 60)
print(f"Agent:      {event.agent_name or event.agent_id}")
print(f"Risk Level: {safety.risk_level.value.upper()}")
...

Credit where it's due — this already guards correctly:

if not sys.stdin.isatty():
    print("Non-interactive session detected. Blocking action.")

It fails closed in non-interactive sessions, which is the right call for a safety tool and means
it won't hang in CI or a daemon. So this isn't a hang bug.

The narrower issue is that it writes to stdout unconditionally, from a library module.
agentwatch is a package people embed inside their agents, and a library that prints to stdout:

  • corrupts structured output. Any consumer emitting JSON on stdout now has a decorated ASCII box
    in the middle of it.
  • can't be suppressed or redirected. There's no logger to configure, no handler to attach, no
    verbosity to turn down.
  • can't be routed. A hosted deployment wants this in its log aggregator, not on a stdout nobody
    reads. Right now there's no seam to do that.

Note the non-interactive branch is the one that hurts most: that's precisely the headless,
embedded, machine-consumed context, and it's the one that still prints.

Suggested fix

Keep the behaviour exactly as it is — including the fail-closed default — but move the output
behind a seam:

  • route the messages through logging (the rest of the library already does), and/or
  • accept an optional on_prompt / renderer callback so the CLI can pass in its Rich renderer and
    an embedded consumer can pass in their own (or nothing).

The CLI keeps its current pretty box; embedders get a stdout they own. Zero change to what gets
blocked or approved.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions