Proposal block formats
The agent uses three fenced markdown blocks to propose changes. Forge parses them out of chat messages, renders them as cards, and applies the changes when you approve.
For the asset-side companion (inline previews + click-to-open buttons that don’t require approval), see Forge-link blocks.

This page documents the wire formats. You don’t normally need to read this. It’s here for skill authors writing instructions for the agent, MCP integrators routing through Forge, and anyone debugging an unexpected card.
forge-propose (memory write)
Section titled “forge-propose (memory write)”Used to add or replace content in .forge/*.md memory files (or ~/.forge/scratchpad/*.md in open mode).
```forge-proposefile: DECISIONS.mdoperation: append---## 2026-04-30 Stamina over mana
Picked stamina to reinforce the survival pillar.```Fields:
- file (required): path relative to the memory base directory. Cannot start with
/or\and cannot contain..(path traversal is rejected). - operation (optional, default
append): one ofappendoroverwrite. Append adds to the end of the file with a separating blank line. Overwrite replaces the file’s content entirely.
The body after --- is the content to write. Markdown is preferred but plain text works.
forge-propose-edit (code edit)
Section titled “forge-propose-edit (code edit)”Used to propose changes to source files. The agent specifies hunks with explicit line ranges, the file’s expected SHA-256, and a commit message for the auto-commit step.
```forge-propose-editfile: src/components/Player.tsxexplanation: Add a debounce to the onChange handlercommit: feat(player): debounce input handler 250msbase_sha256: 3a7c2d8e9f...64hex chars total...e1---@@ 12-12import { useDebounce } from '@/lib/utils';@@ 45-47const debouncedSearch = useDebounce(value, 250);useEffect(() => { if (debouncedSearch) onSearch(debouncedSearch);}, [debouncedSearch, onSearch]);```Fields:
- file (required): path relative to the project root. Same path-traversal rejection rules as
forge-propose. - explanation (optional): one-line summary shown on the card.
- commit (optional, defaults to
chore: edit <file>): the commit message used by auto-commit-on-approve. Conventional Commits style. - base_sha256 (required): the SHA-256 of the file’s contents when the agent read it, lowercase hex, exactly 64 characters. The apply step refuses to write if the file’s current hash doesn’t match.
Hunks are separated by @@ START-END markers:
@@ 12-12: replace line 12 with the lines that follow.@@ 12-15: replace lines 12 through 15 (inclusive, 1-indexed) with what follows.@@ 12: shorthand for@@ 12-12.@@ 12-11: pure insertion before line 12 (start > end means an empty source range).
The replacement lines run until the next @@ ... marker or the end of the block.
forge-propose-skill (new skill)
Section titled “forge-propose-skill (new skill)”Used to add a new auto-skill under ~/.forge/skills/auto/<name>/.
```forge-propose-skillname: phaser-tilemap-collisions------name: phaser-tilemap-collisionsdescription: Phaser 3 tilemap collision setup with Arcade physics.triggers: - phaser tilemap - tile collision - arcade physics tilemapengine: webversion: "1.0"always_on: false---# Tilemap collisions in Phaser 3
...body...```Outer fields:
- name (required): the skill slug. Becomes the directory name under
auto/.
The body after the first --- is itself a complete skill file: YAML frontmatter, then ---, then markdown body. This is the same format as a curated skill (see Skills format).
Composition
Section titled “Composition”Forge applies the three parsers in a stack so a message can contain any mix of them. The MessageList strippers run as:
stripEditProposals(stripSkillProposals(stripProposals(text)))This removes the fenced blocks from the rendered message body so you see the agent’s prose alongside the cards rather than both the prose and the raw block syntax.
Validation
Section titled “Validation”Forge silently ignores malformed blocks (missing required fields, bad SHA, path traversal, etc.) rather than rendering broken cards. If the agent emits something Forge doesn’t accept, the chat shows the agent’s text as if the block weren’t there. This is a deliberate fail-safe.
If you’re writing a skill that asks the agent to emit one of these blocks, double-check the formatting in your skill body. The agent follows skill instructions closely.