Time-based AI agent policies with OPA
Same agent. Different risk by the clock.
Time-based AI agent policies use OPA’s time builtins so tool permissions follow business hours, lunch blocks, and change freezes. Official reference: OPA time builtins. You already have authorize and Terraform attach. This post adds the clock.
Key takeaways
- Drive windows from
input.timestamp, not only wall clock, so tests stay fixed. - Allow-list hours and freeze windows are different postures: one denies everything off-hours; the other denies change actions on weekdays.
- Put fixed timestamps in
opa testfixtures so CI does not depend on wall clock.
Parse the factsheet clock. Do not invent a second time source in Rego if the platform already sent one.
Architecture: time is an input field, not a prompt
Time-based authorization is still the same PDP/PEP loop from authorize. The only change is which factsheet fields Rego reads.
| Source | Use |
|---|---|
input.timestamp |
Platform factsheet clock (RFC3339). Prefer this for business hours and freezes so opa test fixtures stay fixed. |
time.parse_rfc3339_ns |
Turn that string into nanoseconds for time.clock / time.weekday. |
time.now_ns |
Wall clock at evaluate time. Useful for skew or staleness checks; avoid as the only clock in unit tests. |
Two postures share that architecture:
- Allow-list hours (
default allow := false): every tool is denied unless the hour falls in a window. - Change freeze (
default allow := true): most tools pass; change actions fail during weekday business hours.
Both are logic policies. Attach them like any other Rego. They do not need a special runtime mode.
Why prompts fail at “only during business hours”
A persona line that says “do not deploy after 5pm” is advice. An agent investigating an outage at 02:00 will still reach for kubectl apply if that tool is available. Time has to be a field on the enforcement input, not a hope in the system prompt.
Tool-hours allowlist
Opt-in pattern from solutions tool-hours-allowlist.rego: default deny; allow only in morning and afternoon UTC windows; lunch is blocked.
package policy
import rego.v1
default allow := false
factsheet_ts_ns := time.parse_rfc3339_ns(ts) if {
ts := object.get(input, "timestamp", "")
ts != ""
}
hour := time.clock(ns)[0] if {
ns := factsheet_ts_ns
}
in_morning_allow_window if {
hour >= 9
hour < 12
}
in_afternoon_allow_window if {
hour >= 14
hour < 17
}
allow if {
in_morning_allow_window
}
allow if {
in_afternoon_allow_window
}
Lab: samples/aiden-opa-policies/03-business-hours/ with tests for mid-morning, lunch, afternoon, and evening.
Change freeze window
Different question: during Mon-Fri 09:00-17:59 UTC, block change actions, not every tool.
package policy
import rego.v1
default allow := true
change_actions := {"deploy", "apply", "release", "helm_upgrade", "rollout"}
during_business_hours if {
ns := time.parse_rfc3339_ns(input.timestamp)
time.weekday(ns) in {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}
hour := time.clock(ns)[0]
hour >= 9
hour < 18
}
allow := false if {
during_business_hours
input.tool.arguments.action in change_actions
}
allow := false if {
during_business_hours
endswith(input.tool.name, "_execute_command")
contains(lower(input.tool.arguments.command), "kubectl apply")
}
Lab: samples/aiden-opa-policies/04-freeze-and-hitl/freeze/.
How do you verify?
cd samples/aiden-opa-policies
opa test 03-business-hours
opa test 04-freeze-and-hitl/freeze
Use fixed RFC3339 strings in tests (2026-07-16T13:15:00Z for lunch). Do not call time.now_ns inside unit tests if you want green CI at midnight.
Attach either policy with the Terraform pattern from the previous post: type = "logic", file(...) for Rego, then sg_agent_policy_attachment.
Next: when to hard deny versus ask a human. Guardrails and human approval for AI agent tool calls.
Freeze windows belong in Rego, not in a sticky note on the on-call channel. Labs: samples/aiden-opa-policies. To attach on a live tenant: free account then personal access token.
Free to try: create an account, then create a personal access token for Terraform. StackGen / Aiden: app.stackgen.com.
Previous: Manage AI agent policies as code with Terraform. Next: Guardrails and human approval for AI agent tool calls.
FAQ
How do you write time-based AI agent policies with OPA?
Parse input.timestamp with time.parse_rfc3339_ns, then use time.clock and time.weekday. Allow-list windows or deny change actions during freeze hours.
Should policies call time.now_ns or use the factsheet timestamp?
Prefer input.timestamp from the platform factsheet so evaluations and opa test fixtures stay deterministic. time.now_ns is useful for skew checks when you also have a trusted clock.
What is a tool-hours allowlist?
A logic policy that defaults to deny and only sets allow inside named UTC windows, for example morning and afternoon with a lunch gap.
What is a change freeze policy?
A policy that denies deploy, apply, and similar actions during weekday business hours while still allowing reads and status.
Stay in the loop — production notes on AI agents, workflows, and SRE.
Low volume — new posts and curated reading lists. Unsubscribe anytime.