@handlebar/governance-schema 0.1.1-beta.1 → 0.3.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,24 +1,94 @@
1
- # Handlebar Governance Schema
1
+ # Handlebar, Agent Control Layer
2
2
 
3
- Schemas and types for [Handlebar] rules.
3
+ [Handlebar] is a runtime control layer for your AI agents.
4
4
 
5
- ## Getting started
5
+ Enforce deterministic rules on your agents as they act,
6
+ so you can guarantee they don't violate your team's policies.
6
7
 
7
- This package should be used alongside a framework-specific Handlebar SDK,
8
- such as [ai-sdk-v5](https://github.com/gethandlebar/handlebar-js/blob/main/packages/ai-sdk-v5/).
9
- Refer to that package's README for more information.
8
+ This package provides the policy and event types that Handlebar manages.
10
9
 
11
- ## Contributing
10
+ | Without Handlebar | With Handlebar |
11
+ |:------|:------|
12
+ | "Whoops the agent deleted prod DB" | Deterministically block dangerous tool actions. Full auditability into what your agent _tried_ to do. |
13
+ | "Our costs are ballooning with no way to control them" | Track token usage and USD spend, and set hard limits on your agents. When the limit is reached, Handlebar can block the agent from taking further actions. |
14
+ | "Someone convinced the agent to leak another user's emails" | Limit tool permissions to the user. |
15
+ | "The agent is going off-the-rails and spamming heavy APIs" | Set rate limits on tool use and prevent runaway actions |
16
+ | "We can't be sure the agent isn't leaking sensitive data" | Enforce hard data boundaries between tools and your output. Filter PII before it leaks through agent context |
12
17
 
13
- We welcome contributions from the community: bug reports, feedback, feature requests
14
- Please refer to [CONTRIBUTING.md][root_contributing]
15
- for ways you can help,
16
- and guidelines.
18
+ ## Features
17
19
 
18
- ## About Handlebar
20
+ - Collects auditable event logs of your agent's actions
21
+ - Block dangerous tools use (e.g. `send_email(internalAddress) -> PASS | send_email(unknownperson@randomaddress.ru) -> BLOCK`)
22
+ - Block dangerous tool chaining (e.g. `get_pii` -> `send_slack_message -> BLOCK: risk of data exfil`)
23
+ - Require human reviews on dangerous actions
24
+ - Enforce hard cost budgets and token usage limits for your agents
25
+ - Track usage from each enduser and enforce per-user budgets
26
+ - Rate limit agent actions
19
27
 
20
- Find out more at [https://gethandlebar.com][handlebar]
28
+ ## How it works
21
29
 
22
- [handlebar]: https://gethandlebar.com
23
- [root_contributing]: https://github.com/gethandlebar/handlebar-js/blob/main/CONTRIBUTING.md
24
- [discord_invite]: https://discord.gg/Q6xwvccg
30
+ 1. Wrap a Handlebar client (this codebase) around your agent
31
+ 1. The client sends event logs of your agent's actions to the [Handlebar platform][platform], where you can analyse them
32
+ 1. As your agent receives an action from the LLM, Handlebar intercepts and evaluates the proposed action against your configured policies
33
+ 1. If there are violations, Handlebar either permits the action, blocks it, or exits the run
34
+
35
+ ## Get started
36
+
37
+ You will need:
38
+
39
+ - an agent...
40
+ - Wrap your agent with a Handlebar client
41
+ - Connect to the [Handlebar platform][platform]
42
+ - Configure policies to enforce on your agent
43
+
44
+ ### Wrap your agent with Handlebar
45
+
46
+ This repository is a monorepo containing installable packages
47
+ for different JS/TS agent building frameworks. We provide some pre-built wrappers for agent frameworks,
48
+ with more on the way soon. If your agent is not directly supported, you can still easily plug Handlebar into your agent.
49
+
50
+ | Framework | Install command | Where to read more |
51
+ |:---:|:---:|:---:|
52
+ | Vercel ai **Version 5** | `bun i @handlebar/ai-sdk-v5` | [Vercel AI integration guide](../docs/integrations/vercel-ai-sdk.md) |
53
+ | Vercel ai **Version >=6** | Soon... | |
54
+ | Langchain | Soon... it's still being tested 😕 | See the [langchain integration guide](../docs/integrations/langchain.md) |
55
+ | Openai agents | `bun i @handlebar/core` | See the [OpenAI integration guide](../docs/integrations/openai-agents.md)
56
+ | Other JS/TS, and custom agents | `bun i @handlebar/core` | [`packages/core`](../packages/core) |
57
+ | Python agents | Soon... | |
58
+
59
+ ### Connect your agent to the Handlebar platform
60
+
61
+ The client SDKs interact with the Handlebar API to emit agent telemetry and event data it collects,
62
+ and to evaluate your configured policies.
63
+
64
+ Sign up at [`https://app.gethandlebar.com`][platform].\
65
+ If you are waitlisted, [get in touch](#get-in-touch) with us to get access.
66
+
67
+ Once on the platform, create an API key and activate your agent by setting the `HANDLEBAR_API_KEY` environment variable.
68
+
69
+ ### Configure policies to enforce on your agent
70
+
71
+ On the [platform] you can create policies from simple templates: usage limits, dangerous tool use, GDPR, finance agents, and more.
72
+
73
+ Alternatively, run the Handlebar claude code skill to generate rules custom to your agent, by running:
74
+
75
+ ```bash
76
+ npx skills add gethandlebar/agent-skills
77
+ ```
78
+
79
+ Go to the [skill repository](https://github.com/gethandlebar/agent-skills)
80
+ for full instructions.
81
+
82
+ ## Get in touch
83
+
84
+ Please [open an issue](https://github.com/gethandlebar/handlebar-js/issues/new) if you have any feedback, suggestions, or requests for framework support.
85
+ Alternatively, [book a call][calendar] to talk to us about how Handlebar could help to protect your team's agents.
86
+
87
+ ## License
88
+
89
+ Apache 2.0 [`LICENSE`](../LICENSE).
90
+
91
+ [handlebar]: https://www.gethandlebar.com
92
+ [platform]: https://app.gethandlebar.com
93
+ [calendar]: https://calendly.com/arjun-handlebar/30min
94
+ [docs]: https://handlebar.mintlify.app
package/dist/index.js CHANGED
@@ -13785,12 +13785,7 @@ var RunStartedEventSchema = AuditEnvelopeSchema.extend({
13785
13785
  var RunEndedEventSchema = AuditEnvelopeSchema.extend({
13786
13786
  kind: exports_external.literal("run.ended"),
13787
13787
  data: exports_external.object({
13788
- status: exports_external.enum([
13789
- "error",
13790
- "success",
13791
- "timeout",
13792
- "interrupted"
13793
- ]),
13788
+ status: exports_external.enum(["error", "success", "timeout", "interrupted"]),
13794
13789
  totalSteps: exports_external.number().min(0),
13795
13790
  summary: exports_external.string().optional()
13796
13791
  })
@@ -13886,10 +13881,10 @@ var MetricRefSchema = exports_external.discriminatedUnion("kind", [
13886
13881
  ]);
13887
13882
  var MetricWindowConditionSchema = exports_external.object({
13888
13883
  kind: exports_external.literal("metricWindow"),
13889
- scope: exports_external.enum(["agent", "agent_user"]),
13884
+ scope: exports_external.enum(["run", "agent", "agent_user"]),
13890
13885
  metric: MetricRefSchema,
13891
13886
  aggregate: exports_external.enum(["sum", "avg", "max", "min", "count"]),
13892
- windowSeconds: exports_external.number().int().positive(),
13887
+ windowSeconds: exports_external.number().int().positive().optional(),
13893
13888
  filter: exports_external.object({
13894
13889
  toolName: exports_external.union([GlobSchema, exports_external.array(GlobSchema).min(1)]).optional(),
13895
13890
  toolTag: exports_external.union([exports_external.string().min(1), exports_external.array(exports_external.string().min(1)).min(1)]).optional()
@@ -13899,6 +13894,53 @@ var MetricWindowConditionSchema = exports_external.object({
13899
13894
  onMissing: RuleEffectKindSchema.optional()
13900
13895
  }).strict();
13901
13896
 
13897
+ // src/rules/sensitive.ts
13898
+ var SensitiveDataDetectorSchema = exports_external.enum([
13899
+ "email",
13900
+ "email_domain",
13901
+ "phone",
13902
+ "credit_card",
13903
+ "iban",
13904
+ "uk_nino",
13905
+ "ip_address",
13906
+ "url",
13907
+ "jwt",
13908
+ "private_key",
13909
+ "secret_key"
13910
+ ]);
13911
+ var SubConditionValueSchema = exports_external.union([
13912
+ exports_external.string().min(1),
13913
+ exports_external.array(exports_external.string().min(1)).min(1)
13914
+ ]);
13915
+ var SensitiveDataSubConditionSchema = exports_external.discriminatedUnion("check", [
13916
+ exports_external.object({
13917
+ check: exports_external.literal("domain"),
13918
+ op: exports_external.enum(["eq", "neq", "endsWith", "in"]),
13919
+ value: SubConditionValueSchema
13920
+ }).strict(),
13921
+ exports_external.object({
13922
+ check: exports_external.literal("tld"),
13923
+ op: exports_external.enum(["eq", "neq", "in"]),
13924
+ value: SubConditionValueSchema
13925
+ }).strict(),
13926
+ exports_external.object({
13927
+ check: exports_external.literal("scheme"),
13928
+ op: exports_external.enum(["eq", "neq", "in"]),
13929
+ value: SubConditionValueSchema
13930
+ }).strict()
13931
+ ]);
13932
+ var SensitiveDataDetectorEntrySchema = exports_external.object({
13933
+ detector: SensitiveDataDetectorSchema,
13934
+ subCondition: SensitiveDataSubConditionSchema.optional()
13935
+ }).strict();
13936
+ var SensitiveDataConditionSchema = exports_external.object({
13937
+ kind: exports_external.literal("sensitiveData"),
13938
+ target: exports_external.literal("toolArg"),
13939
+ path: exports_external.string().min(1).max(200).optional(),
13940
+ op: exports_external.enum(["anyOf", "allOf"]).default("anyOf"),
13941
+ detectors: exports_external.array(SensitiveDataDetectorEntrySchema).min(1)
13942
+ }).strict();
13943
+
13902
13944
  // src/rules/signals.ts
13903
13945
  var RequireSubjectConditionSchema = exports_external.object({
13904
13946
  kind: exports_external.literal("requireSubject"),
@@ -13931,13 +13973,20 @@ var SignalConditionSchema = exports_external.object({
13931
13973
  // src/rules/time.ts
13932
13974
  var DaySchema = exports_external.enum(["mon", "tue", "wed", "thu", "fri", "sat", "sun"]);
13933
13975
  var TimeHHMMSchema = exports_external.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, 'Expected time in "HH:MM" 24-hour format');
13934
- var TimeGateConditionSchema = exports_external.object({
13935
- kind: exports_external.literal("timeGate"),
13936
- timezone: exports_external.object({
13976
+ var TimezoneSchema = exports_external.discriminatedUnion("source", [
13977
+ exports_external.object({
13937
13978
  source: exports_external.literal("enduserTag"),
13938
13979
  tag: exports_external.string().min(1),
13939
13980
  fallback: exports_external.literal("org").optional()
13940
13981
  }).strict(),
13982
+ exports_external.object({
13983
+ source: exports_external.literal("static"),
13984
+ tz: exports_external.string().min(1)
13985
+ }).strict()
13986
+ ]);
13987
+ var TimeGateConditionSchema = exports_external.object({
13988
+ kind: exports_external.literal("timeGate"),
13989
+ timezone: TimezoneSchema,
13941
13990
  windows: exports_external.array(exports_external.object({
13942
13991
  days: exports_external.array(DaySchema).min(1),
13943
13992
  start: TimeHHMMSchema,
@@ -13965,28 +14014,43 @@ var ToolNameConditionSchema = exports_external.discriminatedUnion("op", [
13965
14014
  value: exports_external.array(exports_external.string().min(1)).min(1)
13966
14015
  }).strict()
13967
14016
  ]);
13968
- var ToolArgConditionSchema = exports_external.discriminatedUnion("type", [
13969
- exports_external.object({
13970
- kind: exports_external.literal("toolArg"),
13971
- type: exports_external.literal("string"),
13972
- op: exports_external.enum(["eq", "neq", "contains", "startsWith", "endsWith", "in"]),
13973
- path: exports_external.string().min(1).max(100),
13974
- value: exports_external.string().min(1).max(1000)
13975
- }),
13976
- exports_external.object({
13977
- kind: exports_external.literal("toolArg"),
13978
- type: exports_external.literal("number"),
13979
- op: exports_external.enum(["eq", "neq", "lt", "lte", "gt", "gte"]),
13980
- path: exports_external.string().min(1).max(100),
13981
- value: exports_external.number()
13982
- }),
14017
+ var ToolArgConditionSchema = exports_external.union([
14018
+ exports_external.discriminatedUnion("type", [
14019
+ exports_external.object({
14020
+ kind: exports_external.literal("toolArg"),
14021
+ type: exports_external.literal("string"),
14022
+ op: exports_external.enum([
14023
+ "eq",
14024
+ "neq",
14025
+ "contains",
14026
+ "startsWith",
14027
+ "endsWith",
14028
+ "in",
14029
+ "regex"
14030
+ ]),
14031
+ path: exports_external.string().min(1).max(100).optional(),
14032
+ value: exports_external.string().min(1).max(1000)
14033
+ }),
14034
+ exports_external.object({
14035
+ kind: exports_external.literal("toolArg"),
14036
+ type: exports_external.literal("number"),
14037
+ op: exports_external.enum(["eq", "neq", "lt", "lte", "gt", "gte"]),
14038
+ path: exports_external.string().min(1).max(100).optional(),
14039
+ value: exports_external.number()
14040
+ }),
14041
+ exports_external.object({
14042
+ kind: exports_external.literal("toolArg"),
14043
+ type: exports_external.literal("boolean"),
14044
+ op: exports_external.literal("eq"),
14045
+ path: exports_external.string().min(1).max(100).optional(),
14046
+ value: exports_external.boolean()
14047
+ })
14048
+ ]),
13983
14049
  exports_external.object({
13984
14050
  kind: exports_external.literal("toolArg"),
13985
- type: exports_external.literal("boolean"),
13986
- op: exports_external.literal("eq"),
13987
- path: exports_external.string().min(1).max(100),
13988
- value: exports_external.boolean()
13989
- })
14051
+ op: exports_external.enum(["exists", "notExists"]),
14052
+ path: exports_external.string().min(1).max(100)
14053
+ }).strict()
13990
14054
  ]);
13991
14055
  var ToolTagConditionSchema = exports_external.discriminatedUnion("op", [
13992
14056
  exports_external.object({
@@ -14005,10 +14069,22 @@ var ToolTagConditionSchema = exports_external.discriminatedUnion("op", [
14005
14069
  tags: exports_external.array(exports_external.string().min(1)).min(1)
14006
14070
  }).strict()
14007
14071
  ]);
14072
+ var SequenceEntrySchema = exports_external.union([
14073
+ GlobSchema,
14074
+ exports_external.object({
14075
+ by: exports_external.literal("toolName"),
14076
+ patterns: exports_external.array(GlobSchema).min(1)
14077
+ }).strict(),
14078
+ exports_external.object({
14079
+ by: exports_external.literal("toolTag"),
14080
+ tags: exports_external.array(exports_external.string().min(1)).min(1),
14081
+ op: exports_external.enum(["anyOf", "allOf"]).optional()
14082
+ }).strict()
14083
+ ]);
14008
14084
  var SequenceConditionSchema = exports_external.object({
14009
14085
  kind: exports_external.literal("sequence"),
14010
- mustHaveCalled: exports_external.array(GlobSchema).min(1).optional(),
14011
- mustNotHaveCalled: exports_external.array(GlobSchema).min(1).optional()
14086
+ mustHaveCalled: exports_external.array(SequenceEntrySchema).min(1).optional(),
14087
+ mustNotHaveCalled: exports_external.array(SequenceEntrySchema).min(1).optional()
14012
14088
  }).strict().refine((v) => v.mustHaveCalled?.length || v.mustNotHaveCalled?.length, "sequence requires mustHaveCalled and/or mustNotHaveCalled");
14013
14089
  var MaxCallsSelectorSchema = exports_external.discriminatedUnion("by", [
14014
14090
  exports_external.object({ by: exports_external.literal("toolName"), patterns: exports_external.array(GlobSchema).min(1) }).strict(),
@@ -14020,7 +14096,10 @@ var MaxCallsSelectorSchema = exports_external.discriminatedUnion("by", [
14020
14096
  var MaxCallsConditionSchema = exports_external.object({
14021
14097
  kind: exports_external.literal("maxCalls"),
14022
14098
  selector: MaxCallsSelectorSchema,
14023
- max: exports_external.number().int().nonnegative()
14099
+ max: exports_external.number().int().nonnegative(),
14100
+ windowSeconds: exports_external.number().int().positive().optional(),
14101
+ per: exports_external.enum(["agent", "agent_user"]).optional(),
14102
+ tagFilter: exports_external.array(exports_external.string().min(1)).min(1).optional()
14024
14103
  }).strict();
14025
14104
 
14026
14105
  // src/rules/condition.ts
@@ -14036,17 +14115,19 @@ var BaseRuleConditionSchema = exports_external.union([
14036
14115
  MetricWindowConditionSchema,
14037
14116
  TimeGateConditionSchema,
14038
14117
  RequireSubjectConditionSchema,
14039
- SignalConditionSchema
14118
+ SignalConditionSchema,
14119
+ SensitiveDataConditionSchema
14040
14120
  ]);
14121
+ var LazyRuleConditionSchema = exports_external.lazy(() => RuleConditionSchema);
14041
14122
  var AndConditionSchema = exports_external.object({
14042
14123
  kind: exports_external.literal("and"),
14043
- all: exports_external.array(BaseRuleConditionSchema).min(1)
14124
+ all: exports_external.array(LazyRuleConditionSchema).min(1)
14044
14125
  }).strict();
14045
14126
  var OrConditionSchema = exports_external.object({
14046
14127
  kind: exports_external.literal("or"),
14047
- any: exports_external.array(BaseRuleConditionSchema).min(1)
14128
+ any: exports_external.array(LazyRuleConditionSchema).min(1)
14048
14129
  }).strict();
14049
- var NotConditionSchema = exports_external.object({ kind: exports_external.literal("not"), not: BaseRuleConditionSchema }).strict();
14130
+ var NotConditionSchema = exports_external.object({ kind: exports_external.literal("not"), not: LazyRuleConditionSchema }).strict();
14050
14131
  var RuleConditionSchema = exports_external.union([
14051
14132
  BaseRuleConditionSchema,
14052
14133
  AndConditionSchema,