Policy reference

Constrain agent work with reviewable, repo-owned rules.

Guardrails are the safety layer between agent intent and target repo mutation. They make policy explicit: which roles receive which warnings, which writes are blocked, which secret patterns stop commits, and how operators review or retire policy over time.

Source of truth: this reference owns guardrail schema and matching behavior. Use security and governance for the control-boundary explanation and remember that YAML hard rules are syntactic checks, not full semantic security review.

Mental Model

MARS uses guardrails in two complementary ways. Repo-owned YAML rules define target-specific policy, while built-in runtime policy blocks unsafe tool behavior such as secret leakage, dangerous shell commands, dirty generated output, and unreviewable blast radius.

LayerUser controlsEffect
Advisory rulesseverity: advisoryAdded to role context. The model is warned, but the rule does not mechanically block a write.
Hard rulesseverity: hard with a content patternChecked by the guardrails engine and blocks matching file content for matching roles.
Secret scanningmars guardrails secret-scan and optional hookFinds common credential patterns with redacted output and exits non-zero on findings.
Runtime policyTool allowlists, trust, and built-in policy checksPrevents unsafe tool calls and oversized or untracked mutations before they become accepted work.
Useful rule of thumb: put project conventions and target-specific restrictions in .harness/guardrails/. Leave general tool safety, shell safety, and workspace hygiene to the built-in policy layer.

Files And Attachment

Guardrail files live inside the target harness and are attached per role from .harness/manifest.yaml. A role only receives the guardrail files listed on that role.

Directory layout

.harness/
|-- manifest.yaml
|-- roles/
|-- guardrails/
|   |-- safety.yaml
|   `-- conventions.yaml
`-- knowledge/

Role attachment

roles:
  engineer:
    prompt: roles/engineer.md
    tools: [file_read, file_write, shell_exec, grep]
    guardrails:
      - guardrails/safety.yaml
      - guardrails/conventions.yaml

Safe inspection

mars run engineer --repo /path/to/target-repo --dry-run
mars guardrails secret-scan --repo /path/to/target-repo --staged

Use dry-run to see assembled advisory context before calling a model.

Rule Schema

A guardrail file has a top-level rules list. MARS defaults missing scope to global, missing severity to advisory, and missing creation time to the time the file is loaded.

rules:
  - id: no-hardcoded-secrets
    name: No hardcoded secrets
    severity: hard
    scope: global
    pattern: '(?i)(password|secret|api_key|token)\s*[:=]\s*["''][^"'']{8,}'
    file_pattern: '*.go'
    message: Do not hardcode secrets. Use environment variables or local secret storage.
    stale_days: -1
FieldRequired?User behavior
idYesStable machine-readable identifier. Use lower-kebab-case and do not reuse it for a different policy.
nameYesShort human label shown in violations and advisory context.
severityNoadvisory or hard. Missing severity defaults to advisory.
scopeNoglobal or a role name. Missing scope defaults to global.
patternNoRE2-compatible content regex. Invalid regex fails closed when rules are loaded.
file_patternNoGlob matched against the file basename, such as *.go or *.sql.
messageYesActionable remediation shown to agents and operators.
stale_daysNo0 or omitted uses the default review window. A negative value means never stale.

Matching Semantics

Understanding matching prevents surprise blocks and false confidence. Guardrails are intentionally syntactic in the current implementation: regex content checks, role scope, and basename file glob checks.

Role scope

scope: global applies to every role that loads the file. A role name such as engineer applies only to that role.

Content regex

pattern is compiled before execution. Invalid regexes reject the rule file instead of running under unknown policy.

File glob

file_pattern uses basename matching. *.go matches internal/app/main.go; path-prefix matching is not part of this v1 rule engine.

Hard rule trigger

A hard rule blocks when the role scope matches, the file glob matches, and the content regex matches. A hard rule without pattern is not useful as a file-content blocker.

Advisory prompt

Advisory rules are deduplicated by id and inserted once into the role context for matching roles.

V1 boundary

AST-aware checks, semantic validation, and path-prefix predicates belong to future or built-in policy surfaces, not the YAML rule matcher.

Rule Examples

Block hardcoded secrets

rules:
  - id: no-hardcoded-secrets
    name: No hardcoded secrets
    severity: hard
    scope: global
    pattern: '(?i)(password|secret|api_key|token)\s*[:=]\s*["''][^"'']{8,}'
    message: Do not hardcode secrets. Use environment variables or .harness/.env.local.

Protect migration files

rules:
  - id: no-drop-table
    name: No destructive migrations
    severity: hard
    scope: engineer
    file_pattern: '*.sql'
    pattern: '(?i)\bDROP\s+TABLE\b'
    message: Destructive migrations need explicit human approval and a rollback plan.

Warn reviewers about API compatibility

rules:
  - id: public-api-compatibility
    name: Preserve public API
    severity: advisory
    scope: reviewer
    message: Check exported names, CLI flags, config keys, and documented behavior before approval.

Secret Scan Command

mars guardrails secret-scan scans common credential shapes and returns a blocking exit code when findings exist. Output includes file, line, and pattern name; the matched value is redacted.

Scan tracked and untracked repo files

mars guardrails secret-scan --repo /path/to/target-repo

Scan staged changes only

mars guardrails secret-scan --repo /path/to/target-repo --staged

Use machine-readable output

mars guardrails secret-scan --repo /path/to/target-repo --json
Pattern classExamples caughtNotes
AWS access keyAKIA...Common long-lived AWS key prefix.
GitHub tokenghp_, gho_, ghs_Matched value is redacted in text and JSON output.
Private key blockRSA, DSA, EC, OpenSSH, or PGP private key header.Treat as leaked until rotated.
Password in URLCredentials embedded before @.Remove the credential from source and history as needed.
Generic API key assignmentapi_key, secret_key, access_token.Review false positives carefully; do not commit real values.

The scanner skips .git/ and the ignored local secret file .harness/.env.local. Commit only .harness/.env.example with environment variable names, not values.

Optional Git Hooks

The hook installer adds an idempotent MARS-managed block to the target repo's pre-commit hook. The hook runs staged secret scanning before a local commit completes.

Install or refresh the hook

mars guardrails install-hooks --repo /path/to/target-repo
mars guardrails install-hooks --repo /path/to/target-repo --json

What the managed block runs

mars guardrails secret-scan --repo /path/to/target-repo --staged

When to install it

Install it for local developer safety. Keep CI or release gates separate if your team needs server-side enforcement.

Stale Rule Review

Guardrails should age on purpose. A stale rule is not necessarily wrong; it is a signal to review whether the policy still describes the current product, team, and agent behavior.

SettingMeaningUse it for
OmittedDefault review window.Most rules.
stale_days: 0Default review window.Equivalent to omission in the current engine.
stale_days: 30Review after 30 days from creation/load time.Temporary conventions and newly tuned policies.
stale_days: -1Never stale.Permanent safety rules such as no committed secrets.

If a stale rule still matters, keep it and refresh the rationale in the rule message or adjacent docs. If it produces false positives, narrow the regex, add a file_pattern, change it to advisory, or remove it with a commit that explains why.

Overrides And Break Glass

The guardrails engine has an override model for active hard-rule exemptions, but users should treat overrides as exceptional. There is no general mars guardrails bypass command in the public guardrails CLI. Prefer fixing the violation or narrowing an overbroad rule in git.

Good reason

The rule is correct, but a one-off human-approved operation needs a time-bounded exception.

Bad reason

The rule fires often during normal work. That means the rule should be refined or converted to advisory.

Audit expectation

Record who approved the exception, which rule ID was bypassed, why, and when the exception expires.

Safer alternative

Commit a narrower policy change and release notes so future agents inherit the corrected behavior.

Authoring Workflow

  1. Start advisory

    Use severity: advisory while observing whether the instruction helps roles make better choices.

  2. Promote only deterministic checks

    Use severity: hard for syntactic checks with a reliable regex and a clear remediation path.

  3. Attach narrowly

    List the rule file only on roles that need it, and use role-specific scope when possible.

  4. Validate before relying on it

    mars run engineer --repo /path/to/target-repo --dry-run
    mars guardrails secret-scan --repo /path/to/target-repo --staged
    mars doctor --repo /path/to/target-repo --json
  5. Commit the policy and rationale

    Guardrail changes are repo-owned behavior. Commit the YAML and any affected docs together.

Troubleshooting

SymptomLikely causeNext action
Role ignores a ruleThe role does not list that guardrail file, or the rule is scoped to another role.Check .harness/manifest.yaml and the rule scope.
Hard rule never blocksThe rule has no pattern, the file basename misses file_pattern, or the regex does not match.Test the regex, remove over-narrow file globbing, or make it advisory.
Rule file fails to loadInvalid YAML or invalid regex.Fix the parse error before running agents; invalid policy should fail closed.
Secret scan blocks commitA staged or repo file matches a credential pattern.Remove the value, rotate it if real, and rerun mars guardrails secret-scan --staged.
False positive in secret scanA test fixture or placeholder looks like a secret.Use safer placeholder strings. Do not weaken real secret patterns casually.
Hook install failsThe path is not a git checkout or the hook file is not writable.Run from the target repo, fix permissions, then rerun install-hooks.
Rule feels too broadContent regex is too general or applies globally.Add file_pattern, scope it to one role, or make it advisory first.