v0.4.0

Rule modes

The rule_mode values (always, glob, auto, explicit) and how each harness honors them.

A rule artifact is passive context the harness loads automatically. The rule_mode field controls when:

ModeLoaded when…Required field
alwaysThe agent session starts (or every turn).none
globA file matching the glob pattern is touched in the session.rule_globs
autoThe harness's autoload heuristic decides this rule's description matches.rule_description
explicitThe user references the rule by name.none

Default is always if you don't set the field.


When to use each mode

always for project-wide guidance every session needs. Style guides, security policies, "you are a senior X engineer" framing.

yaml
type: rule
name: house-style
rule_mode: always

glob for type-specific guidance. Load the React rule only when *.tsx is involved; load the SQL rule only when *.sql is touched.

yaml
type: rule
name: react-style
rule_mode: glob
rule_globs: "src/**/*.tsx,src/**/*.ts"

auto for domain rules where the trigger is fuzzy. The harness's autoload heuristic uses the description to score relevance against the current situation.

yaml
type: rule
name: db-migration-checks
rule_mode: auto
rule_description: "Apply when working with database migrations or schema changes"

explicit for rules so specific the user wants to invoke them deliberately. The harness materializes them but doesn't auto-load; the user references the rule by name (slash command, @rule-name, etc.).

yaml
type: rule
name: incident-response
rule_mode: explicit

How each harness honors them

The harness adapter does the translation at materialization time. Each adapter writes the rule into the harness's native format using the closest equivalent it has. When a harness cannot honor a mode natively, the adapter falls back to an always-loaded block. A rule that declares target_harnesses: draws an ingest lint warning for a ⚠ mode and a lint error for a ✗ mode on a named harness. Without target_harnesses:, a ✗ mode is refused at materialization when the rule loads onto that harness (§6.9).

Modeclaude-codeclaude-desktopclaude-coworkcursorcodexopencodegeminipihermes
always
glob
auto
explicit

Legend: ✓ supported natively, ⚠ supported via fallback (ingest lint warns when a declared target_harnesses: names the harness, and materialization emits the degraded fallback), ✗ not supported (ingest lint errors when a declared target_harnesses: names the harness, and materialization onto that harness otherwise fails per §6.9). This table mirrors the rule_mode rows of the §6.7.1 capability matrix. The claude-cowork cells are ✗ for every mode because Cowork has no project-scope rule surface; a cowork user obtains a rule through the published Claude marketplace (Publishing).


What each adapter writes

AdapterOutput
claude-codeA standalone .claude/rules/<name>.md for every mode, carrying the prose with the Podium-internal fields dropped. always loads at launch and glob writes the native paths: YAML list, both native. auto and explicit fall back to a load-always file (no scoping frontmatter) and draw a lint warning, because Claude Code's .claude/rules/ files have no description-attach or mention-only mode.
cursor.cursor/rules/<name>.mdc for every mode, with the native key set per the mode: always writes alwaysApply: true, glob writes globs: <rule_globs>, auto writes description: <rule_description>, and explicit writes no auto-apply key.
hermes.cursor/rules/<name>.mdc in the Cursor .mdc format for every mode. Hermes natively reads .cursor/rules/*.mdc, root AGENTS.md, and .cursorrules; it does not read .claude/rules/.
codex, opencode, piThe rule body injects into root AGENTS.md between Podium-managed markers. always maps natively; glob, auto, and explicit fall back to always-loaded with a lint warning, because an injected block carries no per-file scoping.
geminiThe rule body injects into root GEMINI.md between Podium-managed markers, with the same always-native, non-always-fallback behavior as the AGENTS.md harnesses.
claude-coworkNo project-scope rule surface. A type: rule artifact on claude-cowork is a ✗ cell that fails materialization with materialize.untranslatable per §6.9, on both podium sync and load_artifact, including the default always mode. A cowork user obtains the rule through the published Claude marketplace (Publishing).
claude-desktopNo project-scope rule surface. Every rule_mode cell is ✗, so a type: rule artifact on claude-desktop fails materialization with materialize.untranslatable per §6.9, on both podium sync and load_artifact, including the default always mode.

Authoring guidance

  • Default to always for guidance you'd want loaded every time. The cost is a few hundred tokens per session; the benefit is consistent behavior.
  • Use glob for type-specific guidance that doesn't need to be loaded for unrelated work. Sharper context, smaller working set.
  • Use auto carefully. It depends on the harness's autoload heuristic, which varies by harness and isn't something you can test deterministically. Write the rule_description as a clear trigger statement rather than a summary.
  • Use explicit for rules with sharp boundaries: incident response procedures, regulatory compliance checklists, anything you'd rather have the user invoke deliberately than have the harness load opportunistically.

Lint behavior

Lint enforces the field requirements per mode:

  • rule_mode: glob requires rule_globs. Missing rule_globs is an ingest error.
  • rule_mode: auto requires rule_description. Missing rule_description is an ingest error.
  • rule_mode: glob with rule_description set: lint warning ("rule-mode 'glob' uses globs only; rule-description is ignored").
  • rule_mode: auto with rule_globs set: lint warning ("rule-mode 'auto' uses description only; rule-globs is ignored").
  • A type other than rule with rule_mode set: lint warning ("rule-mode is only applicable to type: rule").
  • A rule_mode value outside always, glob, auto, and explicit on a type: rule artifact: ingest error (lint.unknown_rule_mode).

When an artifact declares target_harnesses:, ingest lint surfaces a mismatch for any named harness whose cell for the chosen mode is ⚠ (warning) or ✗ (error). When target_harnesses: is absent, ingest stays permissive and an unsupported mode is caught at materialization onto that harness (§6.9). Authors who must use a non-portable mode can declare target_harnesses: in frontmatter to opt out of cross-harness materialization for that artifact.