Autoformalization of Agent Instructions into Policy-as-Code

arXiv cs.AI Papers

Summary

This paper presents an autoformalization pipeline that translates agent prompts, MCP tool descriptions, and natural language policy documents into formally verified policies using an LLM-based generator-critic loop, achieving better coverage than hand-coded enforcement on MedAgentBench.

arXiv:2606.26649v1 Announce Type: new Abstract: Agent safety in high-stakes domains requires formal policy enforcement, but most existing approaches either rely on probabilistic guardrails (fine-tuned classifiers, prompt-based steering) that offer no formal guarantees, or on hand-coded symbolic enforcement that does not scale to the breadth of real policy specifications. We present an autoformalization pipeline that translates agent prompts, MCP tool descriptions, and natural language policy documents into formally verified policies using an LLM-based generator-critic loop. The resulting policies are written in the Cedar Policy Language. On the MedAgentBench benchmark, our autoformalized policies cover substantially more of the source natural-language specification than the hand-coded symbolic enforcement in prior work.
Original Article
View Cached Full Text

Cached at: 06/26/26, 05:14 AM

# Autoformalization of Agent Instructions into Policy-as-Code
Source: [https://arxiv.org/html/2606.26649](https://arxiv.org/html/2606.26649)
###### Abstract

Agent safety in high\-stakes domains requires formal policy enforcement, but most existing approaches either rely on probabilistic guardrails \(fine\-tuned classifiers, prompt\-based steering\) that offer no formal guarantees, or on hand\-coded symbolic enforcement that does not scale to the breadth of real policy specifications\. We present an autoformalization pipeline that translates agent prompts, MCP tool descriptions, and natural language policy documents into formally verified policies using an LLM\-based generator\-critic loop\. The resulting policies are written in the Cedar Policy Language\. On the MedAgentBench benchmark, our autoformalized policies cover substantially more of the source natural\-language specification than the hand\-coded symbolic enforcement in prior work\.

Autoformalization, Policy\-as\-Code, Cedar, Agent Security

\{NoHyper\}

## 1Introduction

![Refer to caption](https://arxiv.org/html/2606.26649v1/pipeline_diagram.png)Figure 1:The policy generation pipeline\. A system prompt, MCP tool definitions, and an \(unstructured\) policy corpus are autoformalized into a verified Cedar policy set by a generator\-critic loop that pairs a hard, deterministic critic \(Cedar parser checks for syntax, schema mismatches, contradictions, and vacuous policies\) with a soft critic \(an LLM\-as\-judge doing semantic alignment and qualitative evaluation against a rubric\)\. If the policies pass both critics, then the generator\-critic loop ends\. The resulting policy set is enforced at runtime by an external policy engine\.Large language models \(LLMs\) have evolved from passive text generators into autonomous agents capable of perceiving environments, planning multi\-step trajectories, and manipulating external tools through frameworks like LangGraph or Amazon Strands\. However, AI agents introduce a strong trade\-off between security and utility: for agents to complete complex tasks autonomously, they often require elevated privileges, and elevated privileges mean a higher\-risk attack surface\. Giving an AI agent elevated privileges is especially risky because LLM\-powered agents are subject to adversarial techniques like prompt injection\.

Current industry practices for securing agent behavior rely heavily on fine\-tuned safety models \(like Llama Guard\(Inan et al\.,[2023](https://arxiv.org/html/2606.26649#bib.bib7)\)\) or prompt\-based steering, using system instructions to direct behavior\. However, classifier\- and prompt\-based guardrails are often inadequate for security\-critical applications because they do not offer formal guarantees\. In this paper, we describe an alternative guardrail approach, using autoformalization and Policy\-as\-Code \(PaC\), which provides strong guarantees about agent behavior\. Our system governs agent behavior via an external deterministic policy engine that evaluates agent actions against formal rules to decide whether those actions are permitted\.

### 1\.1Contributions

We propose a layered autoformalization architecture, termed theVerification Sandwich, to translate natural language agent instructions into formal policy languages\. At runtime, these formal policies are enforced via an agent harness to govern the agent’s actions\. To evaluate our approach, we introduce an open\-source policy harness for agent scaffolds implemented with the Cedar policy language\(Cutler et al\.,[2024](https://arxiv.org/html/2606.26649#bib.bib4)\), and we release this implementation alongside custom Cedar language bindings in Python\.111[https://github\.com/sondera\-ai/sondera\-harness\-python](https://github.com/sondera-ai/sondera-harness-python)Central to this architecture is a policy generation pipeline that automatically converts an agent card \(comprising instructions and tool schemas\) into verified authorization policies\. This work draws inspiration from the LLM Modulo framework\(Kambhampati et al\.,[2024](https://arxiv.org/html/2606.26649#bib.bib9)\)and neurosymbolic AI\.

1. 1\.Thegrounding layer\(bottom\) serves as the foundation for constraining candidate generation\. It extracts entities, identifies tool schemas \(e\.g\., OpenAI JSON schemas\), and defines the principal\-resource\-action ontology\. This layer ensures that the agent operates within a structured environment where every potential action is mapped to real\-world entities and valid system identifiers\.
2. 2\.Themodel layer\(middle\) utilizes the generative capabilities of state\-of\-the\-art models to reason over inputs and generate candidate policies\. It leverages its parametric knowledge to interpret instructions and propose candidate policies that reflect the intended agent logic\.
3. 3\.Thesafety layer\(top\) applies both a hard \(programmatic, deterministically verifiable\) critic and a soft \(LLM\-based\) critic to the candidate policies\. The hard critic can check for problems such as syntax errors or vacuous policies using Cedar’s built\-in static analysis tools\. The soft critic can check for semantic alignment to the original natural language statements, as well as for other qualitative issues defined in a scoring rubric\.

### 1\.2Prior Works

#### 1\.2\.1Autoformalization

Autoformalization is the process of taking informal natural language and translating it into verifiable formal statements that can be processed by machine reasoning\. There has long been interest in modeling computer behavior using mathematical expressions\(Baier & Katoen,[2008](https://arxiv.org/html/2606.26649#bib.bib3)\)\. Previous mathematical research has focused on using formal languages such as LEAN\(de Moura & Ullrich,[2021](https://arxiv.org/html/2606.26649#bib.bib5)\)to reason about the correctness of machine output\. Unfortunately, these functional programming languages require verbose levels of specification at each description, which makes their use cumbersome\. Recent advances in LLMs have made it practical to automate this translation, lowering the manual specification burden that has historically limited the adoption of formal methods\. Of particular interest to our use is the ability of autoformalization to mathematically verify the non\-deterministic LLM\-generated output\(Weng et al\.,[2025](https://arxiv.org/html/2606.26649#bib.bib14)\)\.

#### 1\.2\.2Contextual Agent Policies

As AI agents have arisen with the ability to autonomously control and call tools in a loop, the need to define context\-aware policies to govern their behavior has emerged\(Tsai & Bagdasarian,[2025](https://arxiv.org/html/2606.26649#bib.bib13)\)\. Previous research has explored using contextual decision policies to modify AI model behavior\(Seraj et al\.,[2025](https://arxiv.org/html/2606.26649#bib.bib12)\)\. Other authors have explored generating runtime guardrails out of these policies\(Kholkar & Ahuja,[2025](https://arxiv.org/html/2606.26649#bib.bib11)\)or learning policies by mining agent trajectories\(Abaev et al\.,[2026](https://arxiv.org/html/2606.26649#bib.bib1)\)\.

#### 1\.2\.3Cedar Policy Language

To enforce these types of agent policies, a policy language provides a variety of attractive features including human readable language\(Amazon Web Services,[2025](https://arxiv.org/html/2606.26649#bib.bib2)\)and policies, logical correctness guarantees via theorem provers, validation to catch both syntax and expression errors, and compiled speed\. Existing policy languages were evaluated and for this research the Cedar authorization language open sourced by Amazon Web Services was chosen\(Cutler et al\.,[2024](https://arxiv.org/html/2606.26649#bib.bib4)\)\. While highly performant, Cedar is also easily readable and writable by non\-domain experts\(Kaoudis & Smith,[2024](https://arxiv.org/html/2606.26649#bib.bib10)\)\.

## 2Approach

We apply autoformalization to transform natural language intent from system instructions, MCP tool definitions, and natural language policy documents into formal policies\-as\-code written in the Cedar policy language\. These policies are then used to control runtime agent behavior\. Our pipeline for the autoformalization process is shown in Figure[1](https://arxiv.org/html/2606.26649#S1.F1)\.

The Cedar language allows optional enforcement of a schema, which we find useful as a check on automatically generated policies\. We generate this schema programmatically from the MCP tool definitions\.

We then provide the Cedar schema to a generator\-critic loop \(Figure[1](https://arxiv.org/html/2606.26649#S1.F1)\), along with the agent system prompt, tool definitions, and policy documents\. The generator\-critic loop first uses an LLM to generate a candidate set of policies, which are then checked by a hard critic and a soft critic:

1. 1\.Hard Critic: This component performs a strict, deterministic check of the Cedar policy syntax, enforces schema compliance, and checks for logical contradictions \(i\.e\., a set of policies that can never be satisfied due to conflicting policies\)\.
2. 2\.Soft Critic: Acting as an LLM\-as\-a\-judge, the soft critic evaluates the semantic alignment of the policy against a predefined rubric\. It ensures that the formal logic accurately reflects the spirit of the original instructions and policy documents\.

Feedback from the soft and hard critics is provided back to the policy generator, and this generator\-critic loop continues iteratively to refine the candidate policies\. Once the policy set reaches a certain quality threshold as judged in the hard critic step, the final Cedar policy set is output\. Together, these stages instantiate theVerification Sandwich: the grounding layer produces the Cedar schema, the model layer is the policy generator, and the safety layer is the hard\- and soft\-critic pair\.

## 3Evaluation

We evaluate our approach against the MedAgentBench experiment of Hong et al\.’s symbolic guardrails work\(Hong et al\.,[2026](https://arxiv.org/html/2606.26649#bib.bib6)\)\. MedAgentBench\(Jiang et al\.,[2025](https://arxiv.org/html/2606.26649#bib.bib8)\)is a capability benchmark for tool\-using electronic medical record \(EMR\) agents and contains no safety policy of its own\. Hong et al\. therefore authored a synthetic natural language policy of 88 rules \(drafted by GPT\-5\.2 and expanded via STPA hazard analysis\) and handwrote symbolic guardrails for 23 of those rules\. We feed the same policy through our autoformalization pipeline to produce Cedar policies, evaluating on enforcement coverage rather than agent utility\.

Besides using the natural language policy to generate Cedar rules via our autoformalization pipeline, we also used Claude Opus 4\.7 to transcribe additional Fast Healthcare Interoperability Resources \(FHIR\) constraints from Hong et al\.’s reference MCP server\(Hong et al\.,[2026](https://arxiv.org/html/2606.26649#bib.bib6)\)into Cedar rules\. These additional rules are not derivable from the policy text alone and are therefore required for a fair head\-to\-head comparison with Hong et al\. We annotated each Cedar rule with a source annotation marking its lineage, which allows us to separate the rules into two buckets \(policy\.md or MCP\)\. We do not encode specific benchmark instances or data\-specific constants, but merely aim for parity with the narrowness of the MCP implementation\.

We used an ETL pipeline to ingest and normalize the trajectories from the original MedAgentBench dataset so that we could replay them through our Cedar policy engine for evaluation\.

Experimental Setup\.The autoformalization pipeline used in these experiments is realized as follows\. The candidate generator is Gemini 3 Pro, prompted with the agent’s system instruction, tool definitions, and the auto\-generated Cedar schema\. The hard verifier invokes the Cedar reference tooling \(Rustcedar\-policyCLI\) for syntax and schema checks and for static analysis that flags vacuous policies and conflicting rules, retrying up to three times with validation errors fed back to the generator\. The soft critic is a two\-stage Judge→\\rightarrowVerifier pipeline \(both Gemini 2\.5 Flash, temperatures 0\.3 and 0\.1\)\.

Our cumulative results are shown in Table[1](https://arxiv.org/html/2606.26649#S3.T1)\. Three conditions are tested\. InRaw, the agent uses raw HTTP GET/POST tools \(MedAgentBench’s default\)\. InBaseline, each HTTP endpoint is wrapped in a typed MCP tool\. InGuardrail, Hong et al\.’s symbolic guardrails are added on top of the Baseline\. The Adversarial dataset replaces benign tasks with prompts designed to manipulate the agent into policy violations\.

DatasetConditionHong et al\.Unsafe↓\\downarrowCedar Block Rate↑\\uparrowOriginalRaw39\.0%30\.3% \(91/300\)OriginalBaseline23\.0%57\.7% \(173/300\)OriginalGuardrail0\.0%55\.7% \(167/300\)AdversarialRaw78\.0%72\.0% \(36/50\)AdversarialBaseline62\.0%82\.0% \(41/50\)AdversarialGuardrail0\.0%85\.7% \(42/49\)

Table 1:Policy violation rates on MedAgentBenchThe Cedar Block Rate is consistently higher than Hong et al\.’s Unsafe rate because our autoformalization pipeline covers more of the policy than Hong et al\.’s manual implementation does\. Hong et al\. hand\-coded symbolic guardrails for 23 of the 88 rules in the synthetic policy; our pipeline produces Cedar policies covering more of the same 88\-rule policy automatically\. Hong et al\.’s Unsafe column counts violations of their 23 implemented rules; the Cedar Block Rate counts violations of our broader autoformalized rule set\. The Guardrail rows make this clearest: Hong et al\.’s 0% is by construction within their 23\-rule scope, while Cedar’s 55\.7% \(Original\) and 85\.7% \(Adversarial\) measure violations of the rest of the policy\. The parenthesized counts in the Cedar Block Rate column refer to trajectories: 91/300 means 91 of the 300 trajectories in that split were blocked by Cedar\.

The trajectory\-level block rate understates a stronger underlying result\. Many MedAgentBench tasks involve only retrieval and never issue a write, i\.e\., they never issue a POST request; since Cedar can deny tool calls but not dialog\-only behavior, trajectories with no write attempt are unblockable by construction\. Decomposing by whether the trajectory contains any write attempt:

DatasetConditionTrajectorieswith POSTCedar Block RateOriginalRaw30089100\.0% \(89/89\)OriginalBaseline3008494\.0% \(79/84\)OriginalGuardrail3008698\.8% \(85/86\)AdversarialRaw5034100\.0% \(34/34\)AdversarialBaseline5033100\.0% \(33/33\)AdversarialGuardrail4932100\.0% \(32/32\)

Table 2:Cedar Block Rate by write attempts\. The Cedar Block Rate denominator is the count of trajectories with at least one POST request\.In the adversarial guardrail condition, all seven trajectories that Cedar "missed" had no POST writes attempted: five had no tool calls at all due to the agent intrinsically refusing before hitting a guardrail, and two more were simply retrievals via GET requests\. 49 adversarial trajectories slipped past the MCP server’s hard gating, but Cedar’s additional deny coverage blocked 42 of them \(85\.7%; Table[1](https://arxiv.org/html/2606.26649#S3.T1)\)\.

The full Cedar policies can be found in the supplemental materials in the appendix\.

## 4Discussion

Deterministic Security vs\. LLM Non\-Determinism\.The robustness of this architecture comes from decoupling policy enforcement from the LLM’s reasoning context\. In traditional agentic workflows, safety instructions are often embedded in the system prompt or with external safety models\. Our findings suggest that by extracting this logic into Cedar policies, we mitigate the risk of jailbreaking and indirect prompt injection\. Because the policies sit outside the context window and are enforced by a deterministic policy evaluator, an attacker cannot "convince" the security layer to ignore its rules\. Furthermore, the implementation of a fail\-closed enforcement mechanism ensures that if the policy engine or the validation harness encounters an error, the agent’s actions are blocked by default, prioritizing safety over availability\.

The Friction\-Utility Trade\-off\.A critical challenge identified in our field testing of this work is the friction introduced by formal policy enforcement\. In high\-stakes environments, there is a tendency to author overly restrictive policies to minimize risk\. If the autoformalization pipeline produces policies that are too narrow, the agent’s utility is severely degraded, leading developers to disable protections entirely\. Achieving the "Goldilocks zone" of policy, where the agent is sufficiently constrained yet remains functional, requires a highly sophisticated Generator\-Critic Loop\. The use of a soft policy critic is essential here, as it can evaluate whether a policy is pragmatically aligned with the user’s intent in a way that a rigid syntax checker cannot\.

The Role of Formal Verification\.The choice of Cedar as the target language is central to the pipeline’s success\. Unlike custom JSON schemas or Python\-based checks, Cedar is formally verified and human\-readable\. This ensures that security engineers can audit the generated policies, providing an auditing capability that is essential for building trust in autonomous systems\. The hard verifier in our pipeline ensures that the LLM cannot confabulate entities, providing a level of type safety that is fundamentally missing from pure\-neural approaches to agent steering\.

## 5Ongoing and Future Work

Cedar is stateless by design, and is often used in conjunction with an entity store\. While this is well\-suited to request\-response authorization, it limits multi\-turn agentic workflows that depend on action ordering or persistent context\. Future work focuses on closing this gap along two axes\.

Temporal Logic Integration: Future research will investigate the incorporation of temporal dependencies, ensuring that an action is only authorized if a specific prerequisite sequence has been formally completed and verified\.

Memory\-Aware Policies:We plan to develop mechanisms that allow the policy engine to reference an agent’s trajectory\. This would enable the system to prevent redundant or conflicting actions across long\-running sessions by checking against a persistent state of prior decisions\.

## References

- Abaev et al\. \(2026\)Abaev, N\., Klimov, D\., Levinov, G\., Mimran, D\., Elovici, Y\., and Shabtai, A\.Agentguardian: Learning access control policies to govern ai agent behavior, 2026\.URL[https://arxiv\.org/abs/2601\.10440](https://arxiv.org/abs/2601.10440)\.
- Amazon Web Services \(2025\)Amazon Web Services\.Writing policies in natural language\.AWS Bedrock AgentCore Documentation, 2025\.URL[https://docs\.aws\.amazon\.com/bedrock\-agentcore/latest/devguide/policy\-natural\-language\.html](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy-natural-language.html)\.Accessed: 2026\-02\-01\.
- Baier & Katoen \(2008\)Baier, C\. and Katoen, J\.\-P\.*Principles of Model Checking*\.The MIT Press, Cambridge, MA, USA, 2008\.ISBN 9780262026499\.
- Cutler et al\. \(2024\)Cutler, J\. W\., Disselkoen, C\., Eline, A\., He, S\., Headley, K\., Hicks, M\., Hietala, K\., Ioannidis, E\., Kastner, J\., Mamat, A\., McAdams, D\., McCutchen, M\., Rungta, N\., Torlak, E\., and Wells, A\.Cedar: A new language for expressive, fast, safe, and analyzable authorization \(extended version\), 2024\.URL[https://arxiv\.org/abs/2403\.04651](https://arxiv.org/abs/2403.04651)\.
- de Moura & Ullrich \(2021\)de Moura, L\. and Ullrich, S\.The lean 4 theorem prover and programming language\.In*Automated Deduction – CADE 28*, volume 12699 of*Lecture Notes in Computer Science*, pp\. 625–635\. Springer, Cham, 2021\.doi:10\.1007/978\-3\-030\-79876\-5\_37\.URL[https://link\.springer\.com/chapter/10\.1007/978\-3\-030\-79876\-5\_37](https://link.springer.com/chapter/10.1007/978-3-030-79876-5_37)\.
- Hong et al\. \(2026\)Hong, Y\., She, Y\., Kang, E\., Timperley, C\. S\., and Kästner, C\.Symbolic guardrails for domain\-specific agents: Stronger safety and security guarantees without sacrificing utility, 2026\.URL[https://arxiv\.org/abs/2604\.15579](https://arxiv.org/abs/2604.15579)\.
- Inan et al\. \(2023\)Inan, H\., Upasani, K\., Chi, J\., Rungta, R\., Iyer, K\., Mao, Y\., Tontchev, M\., Hu, Q\., Fuller, B\., Testuggine, D\., and Khabsa, M\.Llama guard: LLM\-based input\-output safeguard for human\-ai conversations, 2023\.URL[https://arxiv\.org/abs/2312\.06674](https://arxiv.org/abs/2312.06674)\.
- Jiang et al\. \(2025\)Jiang, Y\., Black, K\. C\., Geng, G\., Park, D\., Zou, J\., Ng, A\. Y\., and Chen, J\. H\.MedAgentBench: A virtual EHR environment to benchmark medical LLM agents\.*NEJM AI*, 2\(9\):AIdbp2500144, 2025\.
- Kambhampati et al\. \(2024\)Kambhampati, S\., Valmeekam, K\., Guan, L\., Verma, M\., Stechly, K\., Bhambri, S\., Saldyt, L\., and Murthy, A\.Llms can’t plan, but can help planning in llm\-modulo frameworks, 2024\.URL[https://arxiv\.org/abs/2402\.01817](https://arxiv.org/abs/2402.01817)\.
- Kaoudis & Smith \(2024\)Kaoudis, K\. and Smith, I\.Policy language security comparison and threat model\.Technical report, Trail of Bits, 2024\.URL[https://github\.com/trailofbits/publications/blob/master/reports/Policy\_Language\_Security\_Comparison\_and\_TM\.pdf](https://github.com/trailofbits/publications/blob/master/reports/Policy_Language_Security_Comparison_and_TM.pdf)\.Comparative security assessment of policy languages \(Cedar, Rego, OpenFGA\)\.
- Kholkar & Ahuja \(2025\)Kholkar, G\. and Ahuja, R\.Policy\-as\-prompt: Turning ai governance rules into guardrails for ai agents, 2025\.URL[https://arxiv\.org/abs/2509\.23994](https://arxiv.org/abs/2509.23994)\.
- Seraj et al\. \(2025\)Seraj, R\., Meng, L\., and Sylvain, T\.Contextual bandits with entropy\-based human feedback, 2025\.URL[https://arxiv\.org/abs/2502\.08759](https://arxiv.org/abs/2502.08759)\.
- Tsai & Bagdasarian \(2025\)Tsai, L\. and Bagdasarian, E\.Contextual agent security: A policy for every purpose, 2025\.URL[https://arxiv\.org/abs/2501\.17070](https://arxiv.org/abs/2501.17070)\.
- Weng et al\. \(2025\)Weng, K\., Du, L\., Li, S\., Lu, W\., Sun, H\., Liu, H\., and Zhang, T\.Autoformalization in the era of large language models: A survey, 2025\.URL[https://arxiv\.org/abs/2505\.23486](https://arxiv.org/abs/2505.23486)\.

## Appendix ASupplemental Materials

### A\.1Firing by Bucket

Deny counts by rules showing which are policy text constraints and which represent MCP narrowness\.

RuleFiringsBucket2\_4\_restate\_patient\_before\_write4161 \(policy\.md§2\.4\)5\_1\_writes\_require\_confirmation4161 \(policy\.md§5\.1\)6\_3\_stop\_on\_tool\_error3461 \(policy\.md§6\.3\)5\_9\_service\_request\_priority\_stat2802 \(tools\.py:1223\)default\_allow219\(allow events, not blocks\)2\_1\_patient\_must\_have\_been\_retrieved1752 \(tools\.py:638\)5\_7\_no\_unauthorized\_backdating1741 \(policy\.md§5\.7\)6\_4\_no\_duplicate\_write\_retry1731 \(policy\.md§6\.4\)5\_7\_observation\_must\_have\_issued1492 \(tools\.py:650\)3\_4\_narrow\_query\_count1391 \(policy\.md§3\.4\)5\_6\_duplicate\_detection891 \(policy\.md§5\.6\)5\_7\_service\_request\_authored\_on\_in\_window842 \(tools\.py:1205\)5\_9\_observation\_category\_system812 \(tools\.py:703\)5\_9\_med\_request\_coding\_must\_be\_present632 \(tools\.py:999\)2\_5\_single\_patient\_per\_session501 \(policy\.md§2\.5\)5\_7\_med\_request\_authored\_on\_in\_window432 \(tools\.py:949\)5\_7\_observation\_issued\_in\_window202 \(tools\.py:654\)5\_7\_med\_request\_must\_have\_authoredOn122 \(tools\.py:944\)2\_1\_no\_anonymous\_patient\_query111 \(policy\.md§2\.1\)5\_9\_med\_request\_requires\_medication\_and\_dosing101 \(policy\.md§5\.9, typed\)5\_9\_med\_request\_ndc\_coding42 \(tools\.py:1004\)2\_1\_no\_write\_without\_subject41 \(policy\.md§2\.1\)5\_2\_subject\_linking\_required41 \(policy\.md§5\.2\)5\_11\_subject\_reference\_must\_be\_patient41 \(policy\.md§5\.11\)5\_12\_allergy\_check\_before\_medication31 \(policy\.md§5\.12\)5\_9\_med\_request\_status\_active32 \(tools\.py:990\)3\_1\_purpose\_must\_be\_patient\_care21 \(policy\.md§3\.1\)5\_9\_service\_request\_status\_active12 \(tools\.py:1217\)5\_9\_observation\_category\_display\_required12 \(tools\.py:694\)5\_9\_observation\_category\_required12 \(tools\.py:688\)Table 3:Rule firings by bucket\.
### A\.2Cedar Schema

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41entityAgent=\{

42provider:String,

43\};

44entityUser;

45entityLabel;

46entityTool;

47entityTaint;

48

49

50

51

52entityTrajectory=\{

53step\_count:Long,

54label:Label,

55taints:Set<Taint\>,

56\};

57

58entityMessagein\[Trajectory\]=\{

59content:String,

60role:String,

61\};

62

63

64

65

66

67typeWorkspaceContext=\{

68cwd:String,

69permission\_mode:String,

70transcript\_path:String,

71\};

72

73typeSignatureContext=\{

74matches:Long,

75categories:Set<String\>,

76severity:Long,

77\};

78

79typePolicyContext=\{

80compliant:Bool,

81violations:Set<String\>,

82\};

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104typeSessionContext=\{

105now\_timestamp:String,

106now\_date:String,

107last\_tool\_error:Bool,

108last\_get\_patient\_returned\_multiple:Bool,

109user\_specified\_urgency:Bool,

110user\_specified\_backdate:Bool,

111user\_specified\_correction:Bool,

112user\_confirmed\_allergy\_check:Bool,

113last\_assistant\_restated\_patient:Bool,

114user\_confirmed\_write:Bool,

115pending\_write\_confirmed:Bool,

116current\_call\_is\_duplicate:Bool,

117current\_call\_retries\_failed\_write:Bool,

118current\_call\_patient\_mismatch:Bool,

119current\_call\_is\_backdated:Bool,

120current\_call\_is\_correction:Bool,

121

122

123

124

125

126

127

128

129current\_call\_patient\_unseen:Bool,

130established\_patient\_id?:String,

131prior\_post\_signatures?:Set<String\>,

132failed\_post\_signatures?:Set<String\>,

133seen\_patient\_ids?:Set<String\>,

134\};

135

136

137

138

139

140

141

142

143

144typePreToolUseContext=\{

145workspace:WorkspaceContext,

146signature:SignatureContext,

147policy:PolicyContext,

148label:Label,

149tool:String,

150arguments:String,

151session?:SessionContext,

152\};

153

154action"PreToolUse"appliesTo\{

155principal:\[Agent,User\],

156resource:\[Tool\],

157context:PreToolUseContext,

158\};

159

160typeToolOutputContext=\{

161workspace:WorkspaceContext,

162signature:SignatureContext,

163policy:PolicyContext,

164label:Label,

165content:String,

166session?:SessionContext,

167\};

168

169action"ToolOutput"appliesTo\{

170principal:\[Agent,User\],

171resource:\[Trajectory\],

172context:ToolOutputContext,

173\};

174

175typePromptContext=\{

176workspace:WorkspaceContext,

177signature:SignatureContext,

178label:Label,

179session?:SessionContext,

180\};

181

182action"Prompt"appliesTo\{

183principal:\[Agent,User\],

184resource:\[Message\],

185context:PromptContext,

186\};

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215typeGetObservationInput=\{\_count:Long\};

216typeGetObservationContext=\{

217workspace:WorkspaceContext,

218signature:SignatureContext,

219policy:PolicyContext,

220label:Label,

221input:GetObservationInput,

222session?:SessionContext,

223\};

224action"ToolCall::get\_observation"appliesTo\{

225principal:\[Agent,User\],

226resource:\[Tool\],

227context:GetObservationContext,

228\};

229

230typeGetConditionInput=\{\_count:Long\};

231typeGetConditionContext=\{

232workspace:WorkspaceContext,

233signature:SignatureContext,

234policy:PolicyContext,

235label:Label,

236input:GetConditionInput,

237session?:SessionContext,

238\};

239action"ToolCall::get\_condition"appliesTo\{

240principal:\[Agent,User\],

241resource:\[Tool\],

242context:GetConditionContext,

243\};

244

245typeGetMedicationRequestInput=\{\_count:Long\};

246typeGetMedicationRequestContext=\{

247workspace:WorkspaceContext,

248signature:SignatureContext,

249policy:PolicyContext,

250label:Label,

251input:GetMedicationRequestInput,

252session?:SessionContext,

253\};

254action"ToolCall::get\_medication\_request"appliesTo\{

255principal:\[Agent,User\],

256resource:\[Tool\],

257context:GetMedicationRequestContext,

258\};

259

260typeGetProcedureInput=\{\_count:Long\};

261typeGetProcedureContext=\{

262workspace:WorkspaceContext,

263signature:SignatureContext,

264policy:PolicyContext,

265label:Label,

266input:GetProcedureInput,

267session?:SessionContext,

268\};

269action"ToolCall::get\_procedure"appliesTo\{

270principal:\[Agent,User\],

271resource:\[Tool\],

272context:GetProcedureContext,

273\};

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302typePostObservationInput=\{

303status?:String,

304observation\_category\_present?:Bool,

305observation\_category\_code?:String,

306observation\_category\_system?:String,

307observation\_category\_display?:String,

308issued?:String,

309issued\_in\_window?:Bool,

310\};

311typePostObservationContext=\{

312workspace:WorkspaceContext,

313signature:SignatureContext,

314policy:PolicyContext,

315label:Label,

316input:PostObservationInput,

317session?:SessionContext,

318\};

319action"ToolCall::post\_observation"appliesTo\{

320principal:\[Agent,User\],

321resource:\[Tool\],

322context:PostObservationContext,

323\};

324

325typePostMedicationRequestInput=\{

326status?:String,

327intent?:String,

328medication\_coding\_system?:String,

329medication\_coding\_present:Bool,

330authoredOn?:String,

331authored\_on\_in\_window?:Bool,

332dosing\_complete?:Bool,

333dosing\_explanation\_present?:Bool,

334\};

335typePostMedicationRequestContext=\{

336workspace:WorkspaceContext,

337signature:SignatureContext,

338policy:PolicyContext,

339label:Label,

340input:PostMedicationRequestInput,

341session?:SessionContext,

342\};

343action"ToolCall::post\_medication\_request"appliesTo\{

344principal:\[Agent,User\],

345resource:\[Tool\],

346context:PostMedicationRequestContext,

347\};

348

349

350

351

352

353typePostServiceRequestInput=\{

354status?:String,

355intent?:String,

356priority?:String,

357authoredOn?:String,

358authored\_on\_in\_window?:Bool,

359\};

360typePostServiceRequestContext=\{

361workspace:WorkspaceContext,

362signature:SignatureContext,

363policy:PolicyContext,

364label:Label,

365input:PostServiceRequestInput,

366session?:SessionContext,

367\};

368action"ToolCall::post\_service\_request"appliesTo\{

369principal:\[Agent,User\],

370resource:\[Tool\],

371context:PostServiceRequestContext,

372\};

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

### A\.3Cedar Rules \- 00\_base\.cedar

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48@id\("default\_allow"\)

49@description\("Defaultallowallactions;specificforbidrulesinotherfilesoverridethis"\)

50permit\(principal,action,resource\);

### A\.4Cedar Rules \- 02\_patient\_identity\.cedar

1

2

3

4

5

6

7

8

9@id\("medagentbench\_2\_1\_no\_anonymous\_patient\_query"\)

10@source\("policy\.md§2\.1"\)

11@enforcement\("cedar"\)

12@description\("Requireanunambiguouspatientidentifierbeforeretrievingpatient\-specificclinicalresources;forbidget\_observation/get\_condition/get\_medication\_request/get\_procedurewithnopatient\_id"\)

13forbid\(principal,action,resource\)

14when\{

15action==Action::"PreToolUse"&&

16\(context\.tool=="get\_observation"\|\|

17context\.tool=="get\_condition"\|\|

18context\.tool=="get\_medication\_request"\|\|

19context\.tool=="get\_procedure"\)&&

20contexthasarguments&&

21context\.argumentslike"\*\\"patient\_id\\":null\*"

22\};

23

24@id\("medagentbench\_2\_1\_no\_write\_without\_subject"\)

25@source\("policy\.md§2\.1"\)

26@enforcement\("cedar"\)

27@description\("Requireanunambiguouspatientidentifierbeforecreatinganyclinicalresource;forbidpost\_observation/post\_service\_request/post\_medication\_requestwhosepayloadlacksasubjectreference"\)

28forbid\(principal,action,resource\)

29when\{

30action==Action::"PreToolUse"&&

31\(context\.tool=="post\_observation"\|\|

32context\.tool=="post\_service\_request"\|\|

33context\.tool=="post\_medication\_request"\)&&

34contexthasarguments&&

35\!\(context\.argumentslike"\*\\"subject\\":\{\\"reference\\":\\"Patient/\*"\)

36\};

37

38

39

40

41

42

43

44

45

46

47@id\("medagentbench\_2\_2\_resolve\_multiple\_patient\_matches"\)

48@source\("policy\.md§2\.2"\)

49@enforcement\("cedar\+session"\)

50@description\("Ifmultiplepatientmatchesoccur,stopandrequestadditionalidentifiersuntilexactlyonepatientisconfirmed;forbideverynon\-get\_patientcallwhilelast\_get\_patient\_returned\_multiple==true"\)

51forbid\(principal,action,resource\)

52when\{

53action==Action::"PreToolUse"&&

54context\.tool\!="get\_patient"&&

55context\.tool\!="get\_patient\_extended"&&

56contexthassession&&

57context\.sessionhaslast\_get\_patient\_returned\_multiple&&

58context\.session\.last\_get\_patient\_returned\_multiple==true

59\};

60

61

62

63

64

65

66

67

68

69

70@id\("medagentbench\_2\_4\_restate\_patient\_before\_write"\)

71@source\("policy\.md§2\.4"\)

72@enforcement\("cedar\+session"\)

73@description\("Beforeanywriteaction,restatetheconfirmedpatient\(atleastname\+DOBand/orMRN\)andobtainexplicituserconfirmation"\)

74forbid\(principal,action,resource\)

75when\{

76action==Action::"PreToolUse"&&

77\(context\.tool=="post\_observation"\|\|

78context\.tool=="post\_service\_request"\|\|

79context\.tool=="post\_medication\_request"\|\|

80context\.tool=="post\_request"\)&&

81contexthassession&&

82context\.sessionhaspending\_write\_confirmed&&

83context\.session\.pending\_write\_confirmed==false

84\};

85

86

87

88

89

90

91

92

93

94

95@id\("medagentbench\_2\_5\_single\_patient\_per\_session"\)

96@source\("policy\.md§2\.5"\)

97@enforcement\("cedar\+session"\)

98@description\("Eachsessionpertainstoonlyonepatient;forbidanycallreferencingapatient\_iddifferentfromtheoneestablishedearlierinthetrajectory"\)

99forbid\(principal,action,resource\)

100when\{

101action==Action::"PreToolUse"&&

102contexthassession&&

103context\.sessionhascurrent\_call\_patient\_mismatch&&

104context\.session\.current\_call\_patient\_mismatch==true

105\};

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130@id\("medagentbench\_2\_1\_patient\_must\_have\_been\_retrieved"\)

131@source\("tools\.py:638"\)

132@enforcement\("cedar\+session"\)

133@description\("Forbidpost\_\*whosesubjectpatientwasneverfetched\(orsurfacedinapriortooloutput\)earlierinthetrajectory;softwithin\-trajectoryanalogofthepaper's\_patient\_existFHIR\-DBcheck"\)

134forbid\(principal,action,resource\)

135when\{

136action==Action::"PreToolUse"&&

137\(context\.tool=="post\_observation"\|\|

138context\.tool=="post\_service\_request"\|\|

139context\.tool=="post\_medication\_request"\)&&

140contexthassession&&

141context\.sessionhascurrent\_call\_patient\_unseen&&

142context\.session\.current\_call\_patient\_unseen==true

143\};

### A\.5Cedar Rules \- 03\_privacy\.cedar

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37@id\("medagentbench\_3\_1\_purpose\_must\_be\_patient\_care"\)

38@source\("policy\.md§3\.1"\)

39@enforcement\("cedar"\)

40@description\("Allowlist:PHIaccessrequirespurpose='patientcare'\.Forbidsanyotherpurpose\(research,employmentscreening,marketing,VIPlookup,audit,curiosity,etc\.\)"\)

41forbid\(principal,action,resource\)

42when\{

43action==Action::"PreToolUse"&&

44contexthasarguments&&

45context\.argumentslike"\*\\"purpose\\":\\"\*"&&

46\!\(context\.argumentslike"\*\\"purpose\\":\\"patientcare\\"\*"\)

47\};

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69@id\("medagentbench\_3\_4\_narrow\_query\_count"\)

70@source\("policy\.md§3\.4"\)

71@enforcement\("cedar\+typed"\)

72@description\("Retrieveonlywhat'sneeded:forbidget\_observation/get\_condition/get\_medication\_request/get\_procedurewith\_count\>50"\)

73forbid\(principal,action,resource\)

74when\{

75\(action==Action::"ToolCall::get\_observation"\|\|

76action==Action::"ToolCall::get\_condition"\|\|

77action==Action::"ToolCall::get\_medication\_request"\|\|

78action==Action::"ToolCall::get\_procedure"\)&&

79contexthasinput&&

80context\.inputhas\_count&&

81context\.input\.\_count\>50

82\};

### A\.6Cedar Rules \- 05\_writes\.cedar

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58@id\("medagentbench\_5\_1\_writes\_require\_confirmation"\)

59@source\("policy\.md§5\.1"\)

60@enforcement\("cedar\+session"\)

61@description\("Nowriteswithoutexplicitconfirmationoftheexactintendedcontent;forbidpost\_\*toolcallsunlesscontext\.session\.pending\_write\_confirmed==true"\)

62forbid\(principal,action,resource\)

63when\{

64action==Action::"PreToolUse"&&

65\(context\.tool=="post\_observation"\|\|

66context\.tool=="post\_service\_request"\|\|

67context\.tool=="post\_medication\_request"\|\|

68context\.tool=="post\_request"\)&&

69\!\(contexthassession&&

70context\.sessionhaspending\_write\_confirmed&&

71context\.session\.pending\_write\_confirmed==true\)

72\};

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92@id\("medagentbench\_5\_2\_subject\_linking\_required"\)

93@source\("policy\.md§5\.2"\)

94@enforcement\("cedar\+session"\)

95@description\("Whenasessionpatientisestablished,everywritemustreferenceaPatient/\-prefixedsubject;forbidpost\_\*withnoPatient/refwhilesession\.established\_patient\_idisset"\)

96forbid\(principal,action,resource\)

97when\{

98action==Action::"PreToolUse"&&

99\(context\.tool=="post\_observation"\|\|

100context\.tool=="post\_service\_request"\|\|

101context\.tool=="post\_medication\_request"\)&&

102contexthasarguments&&

103contexthassession&&

104context\.sessionhasestablished\_patient\_id&&

105\!\(context\.argumentslike"\*\\"subject\\":\{\\"reference\\":\\"Patient/\*"\)

106\};

107

108

109

110

111

112

113

114

115

116

117

118

119@id\("medagentbench\_5\_5\_priority\_must\_be\_user\_specified"\)

120@source\("policy\.md§5\.5"\)

121@enforcement\("cedar\+session"\)

122@description\("Priority/urgencyinawritemusttracetoanexplicituserinstruction;forbidstat/urgentpriorityonpost\_service\_requestwhenuserdidnotrequestit"\)

123forbid\(principal,action,resource\)

124when\{

125action==Action::"PreToolUse"&&

126context\.tool=="post\_service\_request"&&

127contexthasarguments&&

128\(context\.argumentslike"\*\\"priority\\":\\"stat\*"\|\|

129context\.argumentslike"\*\\"priority\\":\\"STAT\*"\|\|

130context\.argumentslike"\*\\"priority\\":\\"urgent\*"\|\|

131context\.argumentslike"\*\\"priority\\":\\"asap\*"\|\|

132context\.argumentslike"\*\\"priority\\":\\"ASAP\*"\)&&

133contexthassession&&

134context\.sessionhasuser\_specified\_urgency&&

135context\.session\.user\_specified\_urgency==false

136\};

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154@id\("medagentbench\_5\_6\_duplicate\_detection"\)

155@source\("policy\.md§5\.6"\)

156@enforcement\("cedar\+session"\)

157@description\("Forbidpost\_\*whoseclinical\-fieldssignaturematchesapriorsuccessfulwriteinthesametrajectory"\)

158forbid\(principal,action,resource\)

159when\{

160action==Action::"PreToolUse"&&

161\(context\.tool=="post\_observation"\|\|

162context\.tool=="post\_service\_request"\|\|

163context\.tool=="post\_medication\_request"\)&&

164contexthassession&&

165context\.sessionhascurrent\_call\_is\_duplicate&&

166context\.session\.current\_call\_is\_duplicate==true

167\};

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185@id\("medagentbench\_5\_8\_no\_unauthorized\_corrections"\)

186@source\("policy\.md§5\.8"\)

187@enforcement\("cedar\+session"\)

188@description\("Forbidpost\_\*whosepayloadsuppliesanon\-nullresourceid\(correctionintent\)whentheuserhasnotexplicitlyauthorizedcorrection"\)

189forbid\(principal,action,resource\)

190when\{

191action==Action::"PreToolUse"&&

192\(context\.tool=="post\_observation"\|\|

193context\.tool=="post\_service\_request"\|\|

194context\.tool=="post\_medication\_request"\)&&

195contexthassession&&

196context\.sessionhascurrent\_call\_is\_correction&&

197context\.session\.current\_call\_is\_correction==true&&

198context\.sessionhasuser\_specified\_correction&&

199context\.session\.user\_specified\_correction==false

200\};

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219@id\("medagentbench\_5\_7\_no\_unauthorized\_backdating"\)

220@source\("policy\.md§5\.7"\)

221@enforcement\("cedar\+session"\)

222@description\("Forbidpost\_\*whoseauthoredOn/issued/effectiveDateTimeisonadifferentdatethanthesessionnow,unlesstheuserexplicitlyauthorizedbackdating"\)

223forbid\(principal,action,resource\)

224when\{

225action==Action::"PreToolUse"&&

226\(context\.tool=="post\_observation"\|\|

227context\.tool=="post\_service\_request"\|\|

228context\.tool=="post\_medication\_request"\)&&

229contexthassession&&

230context\.sessionhascurrent\_call\_is\_backdated&&

231context\.session\.current\_call\_is\_backdated==true&&

232context\.sessionhasuser\_specified\_backdate&&

233context\.session\.user\_specified\_backdate==false

234\};

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260@id\("medagentbench\_5\_9\_med\_request\_requires\_medication\_and\_dosing"\)

261@source\("policy\.md§5\.9"\)

262@enforcement\("cedar\+typed"\)

263@description\("MedicationRequestmustincludecompletedosinginstructions\(timing\+route\+doseAndRateperentry,mirroringdata\_model\.py:432\);forbidpost\_medication\_requestwithincompletedosingunlessexplanation\_for\_no\_dosing\_instructionsissupplied"\)

264forbid\(principal,action,resource\)

265when\{

266action==Action::"ToolCall::post\_medication\_request"&&

267contexthasinput&&

268context\.inputhasdosing\_complete&&

269context\.input\.dosing\_complete==false&&

270context\.inputhasdosing\_explanation\_present&&

271context\.input\.dosing\_explanation\_present==false

272\};

273

274@id\("medagentbench\_5\_9\_med\_request\_requires\_medication\_concept"\)

275@source\("policy\.md§5\.9"\)

276@enforcement\("cedar"\)

277@description\("MedicationRequestmustincludeamedicationconcept;forbidpost\_medication\_requestwhosepayloadomitsmedicationCodeableConceptandmedicationReference"\)

278forbid\(principal,action,resource\)

279when\{

280action==Action::"PreToolUse"&&

281context\.tool=="post\_medication\_request"&&

282contexthasarguments&&

283\!\(context\.argumentslike"\*\\"medicationCodeableConcept\\":\*"\)&&

284\!\(context\.argumentslike"\*\\"medicationReference\\":\*"\)

285\};

286

287

288

289

290

291

292

293@id\("medagentbench\_5\_11\_subject\_reference\_must\_be\_patient"\)

294@source\("policy\.md§5\.11"\)

295@enforcement\("cedar"\)

296@description\("subject\.referenceonwrittenresourcesmustbeoftheformPatient/\{patient\_id\};forbidpost\_\*withasubjectofanyotherresourcetype"\)

297forbid\(principal,action,resource\)

298when\{

299action==Action::"PreToolUse"&&

300\(context\.tool=="post\_observation"\|\|

301context\.tool=="post\_service\_request"\|\|

302context\.tool=="post\_medication\_request"\)&&

303contexthasarguments&&

304context\.argumentslike"\*\\"subject\\":\{\\"reference\\":\\"\*"&&

305\!\(context\.argumentslike"\*\\"subject\\":\{\\"reference\\":\\"Patient/\*"\)

306\};

307

308

309

310

311

312

313

314

315

316@id\("medagentbench\_5\_12\_allergy\_check\_before\_medication"\)

317@source\("policy\.md§5\.12"\)

318@enforcement\("cedar\+session"\)

319@description\("BeforepostingaMedicationRequest,theusermustconfirmallergyreview;forbidpost\_medication\_requestunlesscontext\.session\.user\_confirmed\_allergy\_check==true"\)

320forbid\(principal,action,resource\)

321when\{

322action==Action::"PreToolUse"&&

323context\.tool=="post\_medication\_request"&&

324\!\(contexthassession&&

325context\.sessionhasuser\_confirmed\_allergy\_check&&

326context\.session\.user\_confirmed\_allergy\_check==true\)

327\};

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348@id\("medagentbench\_5\_9\_med\_request\_status\_active"\)

349@source\("tools\.py:990"\)

350@enforcement\("cedar\+typed"\)

351@description\("MedicationRequest\.statusmustbe'active'"\)

352forbid\(principal,action,resource\)

353when\{

354action==Action::"ToolCall::post\_medication\_request"&&

355contexthasinput&&

356context\.inputhasstatus&&

357context\.input\.status\!="active"

358\};

359

360

361

362@id\("medagentbench\_5\_9\_med\_request\_intent\_order"\)

363@source\("tools\.py:993"\)

364@enforcement\("cedar\+typed"\)

365@description\("MedicationRequest\.intentmustbe'order'"\)

366forbid\(principal,action,resource\)

367when\{

368action==Action::"ToolCall::post\_medication\_request"&&

369contexthasinput&&

370context\.inputhasintent&&

371context\.input\.intent\!="order"

372\};

373

374

375

376

377

378

379

380

381@id\("medagentbench\_5\_9\_med\_request\_ndc\_coding"\)

382@source\("tools\.py:1004\-1015"\)

383@enforcement\("cedar\+typed"\)

384@description\("MedicationRequestmedicationcodingsystemmustbe'http://hl7\.org/fhir/sid/ndc'"\)

385forbid\(principal,action,resource\)

386when\{

387action==Action::"ToolCall::post\_medication\_request"&&

388contexthasinput&&

389context\.inputhasmedication\_coding\_system&&

390context\.input\.medication\_coding\_system\!="http://hl7\.org/fhir/sid/ndc"

391\};

392

393

394

395@id\("medagentbench\_5\_9\_observation\_status\_final"\)

396@source\("tools\.py:724"\)

397@enforcement\("cedar\+typed"\)

398@description\("Observation\.statusmustbe'final'"\)

399forbid\(principal,action,resource\)

400when\{

401action==Action::"ToolCall::post\_observation"&&

402contexthasinput&&

403context\.inputhasstatus&&

404context\.input\.status\!="final"

405\};

406

407

408

409

410

411

412

413

414@id\("medagentbench\_5\_9\_observation\_category\_valid"\)

415@source\("tools\.py:711"\)

416@enforcement\("cedar\+typed"\)

417@description\("Observationcategory\[0\]\.coding\[0\]\.codemustbe'vital\-signs'or'laboratory'"\)

418forbid\(principal,action,resource\)

419when\{

420action==Action::"ToolCall::post\_observation"&&

421contexthasinput&&

422context\.inputhasobservation\_category\_code&&

423context\.input\.observation\_category\_code\!="vital\-signs"&&

424context\.input\.observation\_category\_code\!="laboratory"

425\};

426

427

428

429@id\("medagentbench\_5\_9\_service\_request\_status\_active"\)

430@source\("tools\.py:1217"\)

431@enforcement\("cedar\+typed"\)

432@description\("ServiceRequest\.statusmustbe'active'"\)

433forbid\(principal,action,resource\)

434when\{

435action==Action::"ToolCall::post\_service\_request"&&

436contexthasinput&&

437context\.inputhasstatus&&

438context\.input\.status\!="active"

439\};

440

441

442

443@id\("medagentbench\_5\_9\_service\_request\_intent\_order"\)

444@source\("tools\.py:1220"\)

445@enforcement\("cedar\+typed"\)

446@description\("ServiceRequest\.intentmustbe'order'"\)

447forbid\(principal,action,resource\)

448when\{

449action==Action::"ToolCall::post\_service\_request"&&

450contexthasinput&&

451context\.inputhasintent&&

452context\.input\.intent\!="order"

453\};

454

455

456

457

458

459

460

461

462

463@id\("medagentbench\_5\_7\_observation\_must\_have\_issued"\)

464@source\("tools\.py:650"\)

465@enforcement\("cedar\+typed"\)

466@description\("Observation\.issuedmustbepresent;forbidpost\_observationthatomitstheissuedtimestamp"\)

467forbid\(principal,action,resource\)

468when\{

469action==Action::"ToolCall::post\_observation"&&

470contexthasinput&&

471\!\(context\.inputhasissued\)

472\};

473

474

475

476@id\("medagentbench\_5\_7\_med\_request\_must\_have\_authoredOn"\)

477@source\("tools\.py:944"\)

478@enforcement\("cedar\+typed"\)

479@description\("MedicationRequest\.authoredOnmustbepresent;forbidpost\_medication\_requestthatomitsit"\)

480forbid\(principal,action,resource\)

481when\{

482action==Action::"ToolCall::post\_medication\_request"&&

483contexthasinput&&

484\!\(context\.inputhasauthoredOn\)

485\};

486

487

488

489@id\("medagentbench\_5\_7\_service\_request\_must\_have\_authoredOn"\)

490@source\("tools\.py:1200"\)

491@enforcement\("cedar\+typed"\)

492@description\("ServiceRequest\.authoredOnmustbepresent;forbidpost\_service\_requestthatomitsit"\)

493forbid\(principal,action,resource\)

494when\{

495action==Action::"ToolCall::post\_service\_request"&&

496contexthasinput&&

497\!\(context\.inputhasauthoredOn\)

498\};

499

500

501

502

503

504

505

506

507

508

509@id\("medagentbench\_5\_9\_observation\_category\_system"\)

510@source\("tools\.py:703"\)

511@enforcement\("cedar\+typed"\)

512@description\("Observationcategorycodingsystemmustbe'http://hl7\.org/fhir/observation\-category'"\)

513forbid\(principal,action,resource\)

514when\{

515action==Action::"ToolCall::post\_observation"&&

516contexthasinput&&

517context\.inputhasobservation\_category\_system&&

518context\.input\.observation\_category\_system\!="http://hl7\.org/fhir/observation\-category"

519\};

520

521

522

523

524

525

526

527

528

529

530

531

532@id\("medagentbench\_5\_9\_med\_request\_coding\_must\_be\_present"\)

533@source\("tools\.py:999"\)

534@enforcement\("cedar\+typed"\)

535@description\("MedicationRequestmedicationCodeableConceptmustincludeacodingwithasystem;forbidpost\_medication\_requestwhosepayloadlacksanycoding\[0\]\.system"\)

536forbid\(principal,action,resource\)

537when\{

538action==Action::"ToolCall::post\_medication\_request"&&

539contexthasinput&&

540context\.inputhasmedication\_coding\_present&&

541context\.input\.medication\_coding\_present==false

542\};

543

544

545

546

547

548

549

550

551

552

553@id\("medagentbench\_5\_9\_service\_request\_priority\_stat"\)

554@source\("tools\.py:1223"\)

555@enforcement\("cedar\+typed"\)

556@description\("ServiceRequest\.prioritymustbe'stat'"\)

557forbid\(principal,action,resource\)

558when\{

559action==Action::"ToolCall::post\_service\_request"&&

560contexthasinput&&

561context\.inputhaspriority&&

562context\.input\.priority\!="stat"

563\};

564

565

566

567

568

569

570

571

572@id\("medagentbench\_5\_9\_observation\_category\_display\_value"\)

573@source\("tools\.py:716"\)

574@enforcement\("cedar\+typed"\)

575@description\("Observationcategory\[0\]\.coding\[0\]\.displaymustbe'VitalSigns'or'Laboratory'"\)

576forbid\(principal,action,resource\)

577when\{

578action==Action::"ToolCall::post\_observation"&&

579contexthasinput&&

580context\.inputhasobservation\_category\_display&&

581context\.input\.observation\_category\_display\!="VitalSigns"&&

582context\.input\.observation\_category\_display\!="Laboratory"

583\};

584

585

586

587

588

589

590

591@id\("medagentbench\_5\_9\_observation\_category\_display\_required"\)

592@source\("tools\.py:694"\)

593@enforcement\("cedar\+typed"\)

594@description\("Observationcategory\[0\]\.coding\[0\]\.displaymustbepresent;forbidpost\_observationwhosecategorycodingomitsdisplay"\)

595forbid\(principal,action,resource\)

596when\{

597action==Action::"ToolCall::post\_observation"&&

598contexthasinput&&

599context\.inputhasobservation\_category\_code&&

600\!\(context\.inputhasobservation\_category\_display\)

601\};

602

603

604

605

606

607

608

609

610

611

612

613@id\("medagentbench\_5\_9\_observation\_category\_required"\)

614@source\("tools\.py:688"\)

615@enforcement\("cedar\+typed"\)

616@description\("Observationmusthaveacategory;forbidpost\_observationwhosepayloadomitscategoryentirely"\)

617forbid\(principal,action,resource\)

618when\{

619action==Action::"ToolCall::post\_observation"&&

620contexthasinput&&

621context\.inputhasobservation\_category\_present&&

622context\.input\.observation\_category\_present==false

623\};

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640@id\("medagentbench\_5\_7\_observation\_issued\_in\_window"\)

641@source\("tools\.py:654"\)

642@enforcement\("cedar\+typed"\)

643@description\("Observation\.issuedmustbewithin1hofthebenchmarkservertime;forbidpost\_observationwhoseissuedfallsoutsidethetolerancewindow"\)

644forbid\(principal,action,resource\)

645when\{

646action==Action::"ToolCall::post\_observation"&&

647contexthasinput&&

648context\.inputhasissued\_in\_window&&

649context\.input\.issued\_in\_window==false

650\};

651

652

653

654

655

656

657@id\("medagentbench\_5\_7\_med\_request\_authored\_on\_in\_window"\)

658@source\("tools\.py:949"\)

659@enforcement\("cedar\+typed"\)

660@description\("MedicationRequest\.authoredOnmustbewithin1hofthebenchmarkservertime;forbidpost\_medication\_requestwhoseauthoredOnfallsoutsidethetolerancewindow"\)

661forbid\(principal,action,resource\)

662when\{

663action==Action::"ToolCall::post\_medication\_request"&&

664contexthasinput&&

665context\.inputhasauthored\_on\_in\_window&&

666context\.input\.authored\_on\_in\_window==false

667\};

668

669

670

671

672

673@id\("medagentbench\_5\_7\_service\_request\_authored\_on\_in\_window"\)

674@source\("tools\.py:1205"\)

675@enforcement\("cedar\+typed"\)

676@description\("ServiceRequest\.authoredOnmustbewithin1hofthebenchmarkservertime;forbidpost\_service\_requestwhoseauthoredOnfallsoutsidethetolerancewindow"\)

677forbid\(principal,action,resource\)

678when\{

679action==Action::"ToolCall::post\_service\_request"&&

680contexthasinput&&

681context\.inputhasauthored\_on\_in\_window&&

682context\.input\.authored\_on\_in\_window==false

683\};

### A\.7Cedar Rules \- 06\_tool\_safety\.cedar

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15@id\("medagentbench\_6\_3\_stop\_on\_tool\_error"\)

16@source\("policy\.md§6\.3"\)

17@enforcement\("cedar\+session"\)

18@description\("Ontoolerrors:stop,reportthefailure,andproposesafenextsteps;donotguessresults"\)

19forbid\(principal,action,resource\)

20when\{

21action==Action::"PreToolUse"&&

22contexthassession&&

23context\.sessionhaslast\_tool\_error&&

24context\.session\.last\_tool\_error==true

25\};

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43@id\("medagentbench\_6\_4\_no\_duplicate\_write\_retry"\)

44@source\("policy\.md§6\.4"\)

45@enforcement\("cedar\+session"\)

46@description\("Forbidpost\_\*whoseclinical\-fieldssignaturematchesapriorfailedwriteinthesametrajectory"\)

47forbid\(principal,action,resource\)

48when\{

49action==Action::"PreToolUse"&&

50\(context\.tool=="post\_observation"\|\|

51context\.tool=="post\_service\_request"\|\|

52context\.tool=="post\_medication\_request"\)&&

53contexthassession&&

54context\.sessionhascurrent\_call\_retries\_failed\_write&&

55context\.session\.current\_call\_retries\_failed\_write==true

56\};

Similar Articles

Governance by Construction for Generalist Agents

arXiv cs.AI

This paper presents CUGA's policy system, a modular policy-as-code layer that enforces governance at multiple checkpoints in LLM agent execution, enabling predictable and auditable behavior without model fine-tuning.