agent-contracts 0.30.3 → 0.31.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 foo-ogawa
3
+ Copyright (c) 2026 foo-log-inc
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -278,6 +278,8 @@ A **Guardrail Policy** defines enforcement strategy for guardrails:
278
278
 
279
279
  * rules — array of enforcement rules mapping guardrails to actions
280
280
  * Each rule specifies: severity (`critical`/`mandatory`/`warning`/`info`), action (`block`/`warn`/`shadow`/`info`), override permissions
281
+ * `action` supports a conditional form for state-dependent enforcement: `{ default: "block", when: { maintenance: "shadow" } }`
282
+ * Available states are declared system-wide via `system.states`
281
283
 
282
284
  ### Handoff Type
283
285
 
@@ -337,6 +339,7 @@ Design regressions become testable.
337
339
  * **Inheritance with merge operators via `extends`**
338
340
  * **Guardrail definitions** for cross-cutting process constraints
339
341
  * **Guardrail policies** with configurable enforcement (block/warn/shadow/info)
342
+ * **State-dependent guardrail action** — `action` accepts a conditional form `{ default, when }` keyed by `system.states` for workspace-mode-aware enforcement
340
343
  * **Software bindings** (DI) for tool-specific guardrail implementation (Cursor, Git, GitHub)
341
344
  * **Guardrail generation** from DSL + policy + bindings via `generate guardrails`
342
345
  * **Navigation index** — compile-time artifact-centric model mapping artifacts to operations, agent permissions, relations, and action routes
@@ -374,6 +377,7 @@ system:
374
377
  - audit
375
378
  - release
376
379
  - reflect
380
+ states: [] # optional — named workspace states for conditional guardrail action
377
381
 
378
382
  agents: {}
379
383
  tasks: {}
@@ -711,7 +715,7 @@ artifacts:
711
715
 
712
716
  ## artifact-contracts integration
713
717
 
714
- agent-contracts integrates with [artifact-contracts](https://github.com/foo-ogawa/artifact-contracts) and [cli-contracts](https://github.com/foo-ogawa/cli-contracts) to provide a unified artifact governance model.
718
+ agent-contracts integrates with [artifact-contracts](https://github.com/foo-log-inc/artifact-contracts) and [cli-contracts](https://github.com/foo-log-inc/cli-contracts) to provide a unified artifact governance model.
715
719
 
716
720
  ### Design principle
717
721
 
@@ -1106,7 +1110,7 @@ VarsSubstitutionError: Undefined variable "repo_url" in value "Repository: ${var
1106
1110
 
1107
1111
  For the full CLI reference with all commands, options, arguments, exit codes, and AI agent policies, see the [CLI Reference](docs/cli-reference.md).
1108
1112
 
1109
- The CLI contract specification is defined in [`cli-contract.yaml`](cli-contract.yaml) using [CLI Contracts](https://github.com/foo-ogawa/cli-contracts). Commands that have side effects declare structured `effects` metadata, and the `--introspect` global option outputs the derived policy as JSON without executing the command.
1113
+ The CLI contract specification is defined in [`cli-contract.yaml`](cli-contract.yaml) using [CLI Contracts](https://github.com/foo-log-inc/cli-contracts). Commands that have side effects declare structured `effects` metadata, and the `--introspect` global option outputs the derived policy as JSON without executing the command.
1110
1114
 
1111
1115
  ### Installation
1112
1116
 
@@ -1149,7 +1153,7 @@ agent-contracts audit --introspect
1149
1153
  agent-contracts validate --introspect
1150
1154
  ````
1151
1155
 
1152
- The output follows the [CLI Contracts](https://github.com/foo-ogawa/cli-contracts) `IntrospectionResult` shape:
1156
+ The output follows the [CLI Contracts](https://github.com/foo-log-inc/cli-contracts) `IntrospectionResult` shape:
1153
1157
 
1154
1158
  ````json
1155
1159
  {
@@ -1536,6 +1540,12 @@ guardrail_policies:
1536
1540
  - guardrail: no-force-push
1537
1541
  severity: critical
1538
1542
  action: block
1543
+ - guardrail: branch-lock
1544
+ severity: critical
1545
+ action:
1546
+ default: block
1547
+ when:
1548
+ maintenance: shadow
1539
1549
  - guardrail: english-only-code
1540
1550
  severity: warning
1541
1551
  action: warn
package/cli-contract.yaml CHANGED
@@ -12,8 +12,8 @@ info:
12
12
  license:
13
13
  name: MIT
14
14
  contact:
15
- name: foo-ogawa
16
- url: https://github.com/foo-ogawa/agent-contracts
15
+ name: foo-log-inc
16
+ url: https://github.com/foo-log-inc/agent-contracts
17
17
 
18
18
  artifact_slots:
19
19
  dsl-definitions:
package/dist/cli.js CHANGED
@@ -49099,10 +49099,16 @@ var GuardrailPolicyRuleEscalationSchema = z6.object({
49099
49099
  target: z6.string(),
49100
49100
  condition: z6.string().optional()
49101
49101
  }).passthrough();
49102
+ var ActionEnum = z6.enum(["block", "warn", "shadow", "info"]);
49103
+ var ConditionalActionSchema = z6.object({
49104
+ default: ActionEnum,
49105
+ when: z6.record(z6.string(), ActionEnum)
49106
+ });
49107
+ var ActionSchema = z6.union([ActionEnum, ConditionalActionSchema]);
49102
49108
  var GuardrailPolicyRuleSchema = z6.object({
49103
49109
  guardrail: z6.string(),
49104
49110
  severity: z6.enum(["critical", "mandatory", "warning", "info"]),
49105
- action: z6.enum(["block", "warn", "shadow", "info"]),
49111
+ action: ActionSchema,
49106
49112
  allow_override: z6.boolean().default(false),
49107
49113
  override_requires: z6.array(z6.string()).optional(),
49108
49114
  escalation: GuardrailPolicyRuleEscalationSchema.optional()
@@ -49134,7 +49140,8 @@ var SystemSchema = z8.object({
49134
49140
  name: z8.string(),
49135
49141
  default_workflow_order: z8.array(z8.string()),
49136
49142
  sections: z8.array(SectionSchema).optional(),
49137
- context_loading: ContextLoadingSchema
49143
+ context_loading: ContextLoadingSchema,
49144
+ states: z8.array(z8.string()).default([])
49138
49145
  }).passthrough();
49139
49146
 
49140
49147
  // src/schema/task.ts
@@ -52246,6 +52253,70 @@ var guardrailPolicyCoverageRule = {
52246
52253
  }
52247
52254
  };
52248
52255
 
52256
+ // src/linter/rules/guardrail-policy-action-state.ts
52257
+ function isConditionalAction(action) {
52258
+ return typeof action === "object" && action !== null && "default" in action;
52259
+ }
52260
+ function collectReferencedWhenStates(dsl) {
52261
+ const referenced = /* @__PURE__ */ new Set();
52262
+ for (const policy of Object.values(dsl.guardrail_policies)) {
52263
+ for (const rule of policy.rules) {
52264
+ if (isConditionalAction(rule.action)) {
52265
+ for (const state of Object.keys(rule.action.when)) {
52266
+ referenced.add(state);
52267
+ }
52268
+ }
52269
+ }
52270
+ }
52271
+ return referenced;
52272
+ }
52273
+ var guardrailPolicyActionStateUndefinedRule = {
52274
+ id: "guardrail-policy-action-state-undefined",
52275
+ description: "Policy rule action.when keys must reference states declared in system.states",
52276
+ run(dsl) {
52277
+ const diagnostics = [];
52278
+ const systemStates = new Set(dsl.system.states ?? []);
52279
+ for (const [policyId, policy] of Object.entries(dsl.guardrail_policies)) {
52280
+ for (let ruleIndex = 0; ruleIndex < policy.rules.length; ruleIndex++) {
52281
+ const rule = policy.rules[ruleIndex];
52282
+ if (!isConditionalAction(rule.action)) continue;
52283
+ for (const state of Object.keys(rule.action.when)) {
52284
+ if (!systemStates.has(state)) {
52285
+ diagnostics.push({
52286
+ ruleId: "guardrail-policy-action-state-undefined",
52287
+ severity: "error",
52288
+ path: `guardrail_policies.${policyId}.rules[${ruleIndex}].action.when.${state}`,
52289
+ message: `Policy rule references state "${state}" in action.when, but it is not declared in system.states`
52290
+ });
52291
+ }
52292
+ }
52293
+ }
52294
+ }
52295
+ return diagnostics;
52296
+ }
52297
+ };
52298
+ var systemStatesUnusedRule = {
52299
+ id: "system-states-unused",
52300
+ description: "Each state in system.states should be referenced by at least one policy rule action.when",
52301
+ run(dsl) {
52302
+ const diagnostics = [];
52303
+ const states = dsl.system.states ?? [];
52304
+ if (states.length === 0) return diagnostics;
52305
+ const referenced = collectReferencedWhenStates(dsl);
52306
+ for (const state of states) {
52307
+ if (!referenced.has(state)) {
52308
+ diagnostics.push({
52309
+ ruleId: "system-states-unused",
52310
+ severity: "info",
52311
+ path: `system.states`,
52312
+ message: `State "${state}" is declared in system.states but not referenced by any policy rule action.when`
52313
+ });
52314
+ }
52315
+ }
52316
+ return diagnostics;
52317
+ }
52318
+ };
52319
+
52249
52320
  // src/linter/rules/yaml-reserved-key-safety.ts
52250
52321
  var YAML_11_RESERVED_KEYS = /* @__PURE__ */ new Set([
52251
52322
  "on",
@@ -53055,6 +53126,8 @@ var builtinRules = [
53055
53126
  artifactOwnershipRule,
53056
53127
  toolCommandsRule,
53057
53128
  guardrailPolicyCoverageRule,
53129
+ guardrailPolicyActionStateUndefinedRule,
53130
+ systemStatesUnusedRule,
53058
53131
  yamlReservedKeySafetyRule,
53059
53132
  artifactRequiredValidationWiringRule,
53060
53133
  taskOutputValidationCompletenessRule,