1
00:00:00,000 --> 00:00:03,920
Picture a headless Codex run in CI that
stops halfway through a task.

2
00:00:03,984 --> 00:00:08,640
Your orchestrator logs it as an
interruption, shrugs, and retries.

3
00:00:08,780 --> 00:00:13,840
The agent hits the same wall, gets denied
the same way, and stops again.

4
00:00:13,954 --> 00:00:17,600
Thanks to Jellypod for helping make this
daily show a reality.

5
00:00:17,747 --> 00:00:22,320
Today is about a setting that gives that
second stop a name your code can read.

6
00:00:23,090 --> 00:00:28,570
The setting is
auto_review.circuit_break_action, and you can now set it to "strict".

7
00:00:29,090 --> 00:00:30,650
The default value is "default".

8
00:00:31,150 --> 00:00:34,850
It lives under an auto_review table in
config.toml.

9
00:00:35,610 --> 00:00:41,370
It came in through pull request 48796,
titled "Add opt in structured errors for

10
00:00:41,470 --> 00:00:46,970
Guardian circuit breaker interruptions,"
which shows up in the 0.159.0 changelog

11
00:00:47,030 --> 00:00:47,310
list.

12
00:00:47,930 --> 00:00:50,210
The app server README documents the
behavior.

13
00:00:50,953 --> 00:00:51,713
Here's the mechanism.

14
00:00:52,353 --> 00:00:56,713
Guardian is the auto review layer that
evaluates actions the agent wants to take.

15
00:00:57,233 --> 00:00:59,333
Each denial counts toward a limit.

16
00:00:59,893 --> 00:01:04,133
When a turn reaches that denial limit, the
circuit breaker trips and the turn is

17
00:01:04,173 --> 00:01:04,693
interrupted.

18
00:01:05,293 --> 00:01:10,893
With strict set, Codex attaches a
TooManyDenials error to TurnAborted.error.

19
00:01:11,533 --> 00:01:15,153
In app server notifications and saved
history, that shows up as

20
00:01:15,233 --> 00:01:20,273
turn.error.codexErrorInfo equal to the
string tooManyDenials.

21
00:01:20,583 --> 00:01:23,143
And the default is the important contrast.

22
00:01:23,271 --> 00:01:26,823
With "default", that error field stays
unset.

23
00:01:27,015 --> 00:01:32,743
Both modes still preserve the warning, the
denial limit, and the interrupted status.

24
00:01:32,930 --> 00:01:35,383
So nothing disappears in default mode.

25
00:01:35,523 --> 00:01:38,583
The turn still ends as interrupted with
the warning.

26
00:01:38,711 --> 00:01:41,543
What's missing is a field that says why.

27
00:01:41,767 --> 00:01:43,647
Why does that matter?

28
00:01:43,727 --> 00:01:46,927
Think about what else produces an
interrupted turn.

29
00:01:47,247 --> 00:01:49,527
A person hits control C.

30
00:01:49,707 --> 00:01:51,407
A network call times out.

31
00:01:51,727 --> 00:01:53,167
A connection drops.

32
00:01:53,307 --> 00:01:57,327
And now Guardian has locked the agent out
after repeated denials.

33
00:01:57,447 --> 00:01:59,487
Those need different responses.

34
00:01:59,847 --> 00:02:04,287
A control C or a dropped connection is
often safe to retry.

35
00:02:04,687 --> 00:02:10,127
A Guardian lockout means the agent kept
proposing things your policy refuses,

36
00:02:10,157 --> 00:02:15,327
whether that's writes outside the allowed
directories, unapproved network access,

37
00:02:15,354 --> 00:02:17,407
or binaries you haven't permitted.

38
00:02:17,767 --> 00:02:22,127
A blind retry just burns time and money to
reach the same lockout.

39
00:02:22,487 --> 00:02:26,186
That's the failure pattern with codex exec
in a pull request bot,

40
00:02:26,367 --> 00:02:29,167
or a supervisor agent running child
agents.

41
00:02:29,847 --> 00:02:34,647
Without a discriminator, the supervisor
can't tell a policy lockout from a flaky

42
00:02:34,707 --> 00:02:35,107
network.

43
00:02:35,707 --> 00:02:40,487
It either retries forever, or it fails
opaquely and nobody on the security side

44
00:02:40,547 --> 00:02:41,087
finds out.

45
00:02:41,967 --> 00:02:44,887
With strict on, you branch on a single
field.

46
00:02:45,498 --> 00:02:46,098
Setup first.

47
00:02:46,878 --> 00:02:53,878
In your user config at
~/.codex/config.toml, or a repository

48
00:02:53,958 --> 00:02:59,938
level .codex/config.toml, add the table
header auto_review and under it

49
00:03:00,518 --> 00:03:02,938
circuit_break_action equal to "strict".

50
00:03:03,458 --> 00:03:04,398
That's the whole change.

51
00:03:05,018 --> 00:03:09,458
Then, in whatever consumes app server
notifications, look at the aborted turn.

52
00:03:10,258 --> 00:03:13,578
The shape from the protocol is a turn with
status interrupted,

53
00:03:14,058 --> 00:03:18,318
and an error object whose codexErrorInfo
is tooManyDenials.

54
00:03:18,667 --> 00:03:20,267
The handler pattern is short.

55
00:03:20,480 --> 00:03:24,907
If the turn status is interrupted, check
whether turn.error,

56
00:03:24,960 --> 00:03:30,427
using optional chaining, has a
codexErrorInfo equal to tooManyDenials.

57
00:03:30,640 --> 00:03:33,147
If it does, do not retry.

58
00:03:33,307 --> 00:03:39,467
Notify a security reviewer with the turn
ID and thread ID and a reason like policy

59
00:03:39,524 --> 00:03:43,227
denial limit, then escalate that thread to
manual review.

60
00:03:43,339 --> 00:03:48,987
Otherwise, treat it as an ordinary
interruption and run your normal recovery path.

61
00:03:49,087 --> 00:03:52,267
Two branches, and the first one protects
you from the loop.

62
00:03:52,445 --> 00:03:54,385
You can also use it for audit.

63
00:03:54,585 --> 00:03:59,505
Log the discriminator with the thread ID
and you get a queryable record of every

64
00:03:59,569 --> 00:04:01,185
time Guardian stopped an agent.

65
00:04:01,295 --> 00:04:06,305
Because it's saved in history too, you can
look back over past threads for it,

66
00:04:06,365 --> 00:04:07,745
not only react live.

67
00:04:08,050 --> 00:04:10,070
Now the caveats, because there are three.

68
00:04:10,490 --> 00:04:12,570
First, it's opt in on purpose.

69
00:04:13,050 --> 00:04:17,370
The pull request says older clients may
not recognize the new error in shared

70
00:04:17,410 --> 00:04:17,790
history.

71
00:04:18,570 --> 00:04:21,890
If you turn on strict, make sure every
client that reads those threads,

72
00:04:22,010 --> 00:04:27,230
including IDE extensions and your own
tooling, handles an unfamiliar error value

73
00:04:27,270 --> 00:04:28,050
without choking.

74
00:04:28,530 --> 00:04:31,090
The default leaves the error unset for
that reason.

75
00:04:31,417 --> 00:04:37,017
Second, and this one catches people:
strict does not emit a separate Error event.

76
00:04:37,097 --> 00:04:41,177
The documentation is explicit that neither
mode emits one.

77
00:04:41,317 --> 00:04:45,737
The information rides on the turn itself,
in turn.error.

78
00:04:45,950 --> 00:04:50,217
So if your integration only listens for an
error notification,

79
00:04:50,270 --> 00:04:52,137
it will never see the circuit breaker.

80
00:04:52,317 --> 00:04:56,377
You have to inspect the aborted or
completed turn payload.

81
00:04:56,677 --> 00:04:57,817
Third, scope.

82
00:04:58,277 --> 00:05:02,437
This fires when the denial limit is
reached, not on every denial.

83
00:05:02,997 --> 00:05:07,317
If Guardian rejects one command and the
agent keeps reasoning and picks a different

84
00:05:07,377 --> 00:05:09,777
approach, you won't see tooManyDenials.

85
00:05:10,277 --> 00:05:14,417
It's a signal that the breaker tripped,
not a per command denial feed.

86
00:05:14,977 --> 00:05:18,877
If you want visibility into individual
denials, this isn't that feature.

87
00:05:19,208 --> 00:05:21,448
A few smaller things from the same
stretch.

88
00:05:21,592 --> 00:05:28,008
Pull request 50094 added stored thread
attachments to the app server.

89
00:05:28,168 --> 00:05:34,808
The method names are
thread/attachment/add, list, and remove,

90
00:05:34,856 --> 00:05:38,488
plus thread/attachmentOwner/list.

91
00:05:38,648 --> 00:05:44,248
You can attach metadata, say a canonical
GitHub pull request URL,

92
00:05:44,301 --> 00:05:46,728
to a thread without loading or resuming
it.

93
00:05:46,888 --> 00:05:52,248
The owner lookup works in reverse, so you
can ask which threads are tied to a given

94
00:05:52,296 --> 00:05:53,128
pull request.

95
00:05:53,527 --> 00:05:59,207
On the terminal side, 0.160.0 added X11
primary selection support.

96
00:05:59,767 --> 00:06:05,187
In fullscreen mode on supported local
Linux X11 terminals, you can select transcript

97
00:06:05,247 --> 00:06:07,307
text and paste with middle click.

98
00:06:08,087 --> 00:06:14,367
Also in 0.160.0, Codex now reclaims unused
SQLite log database pages in the

99
00:06:14,407 --> 00:06:20,207
background, which targets disk growth from
the local logs, pull request 49069.

100
00:06:20,458 --> 00:06:22,698
One more, tied to today's topic.

101
00:06:22,826 --> 00:06:28,378
Pull request 51070 fixed the Guardian
Decisions adapter.

102
00:06:28,591 --> 00:06:34,618
It used to reject developer messages,
including host annotated trusted tool context,

103
00:06:34,698 --> 00:06:37,818
so requests carrying that context couldn't
be classified.

104
00:06:37,978 --> 00:06:43,018
Now developer text annotated with
TrustedTool::KIND is appended to the

105
00:06:43,077 --> 00:06:44,458
classification rubric.

106
00:06:44,645 --> 00:06:49,578
It accepts only a single text part with a
single matching annotation,

107
00:06:49,598 --> 00:06:53,738
and it still rejects other developer
messages and unsupported evidence.

108
00:06:54,090 --> 00:06:56,110
So the takeaway is small and concrete.

109
00:06:56,510 --> 00:07:00,170
If you run Codex unattended, set
circuit_break_action to strict,

110
00:07:00,670 --> 00:07:05,010
check your clients can read the new value,
and branch on tooManyDenials in the turn

111
00:07:05,090 --> 00:07:08,550
error instead of listening for an error
event that never comes.

