Sessions Git Protocol

Session-Aware Git Protocol (SAGP) — mandatory rules for concurrent session management and git discipline

Session-Aware Git Protocol (SAGP) v1.3

Purpose: Ensure agents working concurrently on different sessions never mix changes, always commit logically, and keep the repository clean and navigable.

Concurrent lanes (v1.3): A branch is a shared lane; session ownership is [S{N}.{sub}] on each commit. Several sessions may use one branch (e.g. range lanes like session-264-269_new). Normative model: session-git-concurrent-lanes-spec.md. Manifests stay one file per session (sessions/manifests/S{N}.json); only Git handling is more flexible.


1. Session Lifecycle — The 4 Mandatory Steps

Every agent MUST follow this lifecycle for every task:

INIT → WORK → COMMIT → CLOSE

Step 1: INIT (before writing any code)

1. Call: preflight({ task: "...", sessionNumber: N, subSessionNumber: N.X })
   OR: session({ action: "set", sessionNumber: N, subSessionNumber: X })

2. Verify git branch (lane):
   - Run: `git branch --show-current`
   - The branch must **plausibly relate** to session **N** — e.g. `session-{N}`, or a **range lane** whose name includes **N** (e.g. `session-264-269_new` for session 269). MCP preflight uses a **multi-session** policy by default.
   - If you need a new lane: `git checkout -b session-{A}-{B}` or `session-{N}` as appropriate; coordinate with teammates on shared lanes.
   - If you must switch lanes: stash/commit first, then `git checkout <lane>` (see §5).

3. Update sub-session: always increment subSessionNumber from the last known value
   - Check: session({ action: "get_info" }) or read sessions/manifests/S{N}.json
   - Your sub-session = last sub + 1 (e.g., if last was 144.5, yours is 144.6)

Step 2: WORK (implement the task)

Step 3: COMMIT (after completing a sub-session or logical unit)

1. Stage ONLY files belonging to your sub-session:
   git add <specific-files>

2. Commit with structured message:
   git commit -m "[S{N}.{sub}] type: description"

   Examples:
   - [S144.3] feat: sandbox provider abstraction with strategy pattern
   - [S144.4] fix: observatory dashboard data binding
   - [S139.6] test: A2A protocol integration tests

3. Update session manifest:
   session({ action: "set", sessionNumber: N, subSessionNumber: X })

Step 4: CLOSE (when the sub-session is complete)

1. Verify all changes are committed: git status (should be clean for your files)
2. Log the decision: log_decision({ ... })
3. Report outcome: outcome({ action: "report", ... })
4. If session is fully complete:
   - Land on `main` via **PR** (or controlled merge policy). PR title and merge/squash messages must preserve **session tags** — see [session-git-concurrent-lanes-spec.md](./session-git-concurrent-lanes-spec.md) (§3.5–3.6).
   - OR: leave the lane for manual review

2. Git Branch Protocol

Branch naming (lanes)

Branch Purpose Lifetime
main Stable, tested code Permanent
session-{N} Lane often used for a single session or as a simple name Until merged to main
session-{A}-{B} / session-{A}-{B}_{suffix} Range / shared lane — several concurrent sessions may commit here Until merged to main

Full normative rules: session-git-concurrent-lanes-spec.md

Branch rules

  1. NEVER work on main directly — use a session-* lane (including range lanes)
  2. Do not land unrelated work without attribution — if the lane is shared, use the correct [S{N}.{sub}] per commit; split commits when needed
  3. Check your lane before every commit: git branch --show-current
  4. Create a lane if it doesn't exist: e.g. git checkout -b session-{N} or a range lane agreed with your team

When you need a different lane

# Save current work if you have uncommitted changes
git stash push -m "S{CURRENT}.{sub}: WIP description"

# Switch to the target lane (session-{M} or shared range branch)
git checkout <target-lane>

# Continue working (or pop a stash if resuming)

3. Commit Convention

Message Format

[S{session}.{sub}] type: concise description

Optional body with details.

Types

Type When
feat New feature or capability
fix Bug fix
refactor Code restructuring without behavior change
test Adding or updating tests
docs Documentation only
chore Config, tooling, dependencies
style Formatting, SCSS, visual-only changes

Rules

  1. One commit per sub-session (preferred) or per logical unit
  2. Never accumulate uncommitted changes across sub-sessions — commit before starting a new sub-session
  3. Never commit files from another session — if you find orphaned files, stash them for the right session
  4. Cross-cutting files (CLAUDE.md, AGENTS.md, history.json) commit on the current session branch — they merge naturally

Examples

# Good: specific, traceable
git commit -m "[S144.3] feat: sandbox provider abstraction with strategy pattern"
git commit -m "[S144.4] feat: observability dashboard backend + frontend"
git commit -m "[S139.6] test: A2A protocol integration tests"

# Bad: vague, no session tag
git commit -m "updates"
git commit -m "fix stuff"
git commit -m "WIP"

4. Stash Protocol

When to Stash

Situation Action
Switching to a different session git stash push -m "S{N}.{sub}: description"
Found orphaned files from another session git stash push -m "S{N}: orphaned files" -- file1 file2
Need clean working tree for build/test git stash push -m "S{N}.{sub}: temp stash for testing"

When NOT to Stash

Situation Do This Instead
Completed work Commit it
Permanent storage Commit to the session branch
Backup Push the session branch to remote

Stash Naming Convention

S{session}.{sub}: {description}

Examples:

Stash Commands Quick Reference

# Stash all uncommitted changes
git stash push -m "S{N}.{sub}: description"

# Stash specific files only
git stash push -m "S{N}.{sub}: description" -- path/to/file1 path/to/file2

# List stashes
git stash list

# Pop the most recent stash
git stash pop

# Pop a specific stash
git stash pop stash@{2}

# Apply without removing from stash list (safer)
git stash apply stash@{0}

# Drop a stash after confirming it's applied
git stash drop stash@{0}

5. Concurrent Agent Workflow

Scenario: Two agents working simultaneously (different sessions)

Option A — separate lanes: each checks out a different session-{N} or range lane; no overlap on working tree if branches differ.

Option B — shared lane (common): both work on the same range lane (e.g. session-264-269_new). No conflicts as long as they commit with distinct [S{N}.{sub}] tags and coordinate file overlap like any shared branch.

Agent A (S144)                 Agent B (Session 145)
─────────────────────          ─────────────────────
1. preflight(S144)             1. preflight(S145)
2. git checkout <lane-144>     2. git checkout <lane-145 or same shared lane>
3. Work + commit [S144.x]      3. Work + commit [S145.x]

Scenario: Same agent switching between sessions

1. Working on S144.3 (lane: session-144 or a shared range branch)
2. Need to fix something in S141

   # Save S144 work
   git stash push -m "S144.3: WIP sandbox providers"

   # Switch to S141's lane
   git checkout session-141   # or the lane where S141 work lives

   # Fix the issue
   git add <files> && git commit -m "[S141.15] fix: tauri config update"

   # Return to S144 lane
   git checkout session-144   # or previous shared lane
   git stash pop

   # Continue working on S144.3

Scenario: Discovered orphaned files from another session

PREFERRED (safe): Commit orphaned files from the current branch using cherry-pick

1. Working on S144 (branch: session-144)
2. Notice files that belong to S139 (e.g., A2A tests)

   # Commit ONLY the orphaned files on your current branch with a clear tag
   git add APIs/backend-vitto-api/src/app/a2a/__tests__/
   git commit -m "[S139-orphan] test: A2A integration tests (to cherry-pick to session-139)"

   # Now cherry-pick to the target branch WITHOUT checking it out:
   git stash push --include-untracked -m "SAGP: save state before cherry-pick"
   git checkout session-139
   git cherry-pick <commit-hash>
   git checkout session-144
   git stash pop

   # Remove the orphan commit from session-144 (it now lives on session-139)
   git reset HEAD~1

ALTERNATIVE (when cherry-pick is overkill for small files): Leave a note

   # Stash the orphaned files with a descriptive name
   git stash push -m "S139: orphaned A2A tests - MOVE TO session-139" -- <files>

   # DO NOT checkout old branches in the live workspace
   # Leave the stash for a dedicated cleanup pass or the session owner

CRITICAL: Never checkout old branches in the live workspace

Checking out branches that are far behind the current branch causes the IDE to show thousands of "changes" (build artifacts, generated files, new directories). This is terrifying and risks accidental commits or panic-driven data loss.

If you MUST checkout an old branch:

  1. First verify: git log --oneline session-{OLD} -1 — how old is it?
  2. If more than ~5 commits behind: use cherry-pick instead of checkout
  3. If you must checkout: do it, commit fast, checkout back immediately
  4. NEVER run git add -A or git add . on an old branch — you'll stage build artifacts

6. Session Resolution Protocol (Cleaning Up Mixed Changes)

When uncommitted changes from multiple sessions are mixed on one branch, follow this protocol:

Step 1: Audit

# See all uncommitted changes
git status

# Read session manifests to understand what each session was working on
cat sessions/manifests/S144.json | jq '.subSessions[-1].focus'

Step 2: Group

Categorize every changed file by session. Use these heuristics:

Step 3: Isolate (stash per session)

# For each non-current session, stash its files:
git stash push -m "S141: desktop app files" -- \
  apps/vitto-desktop/src-tauri/tauri.conf.json \
  deployment/cloudflare/vitto-updater-worker/

git stash push -m "S139: A2A tests" -- \
  APIs/backend-vitto-api/src/app/a2a/__tests__/

Step 4: Commit current session

# Now only current session files remain
git add -A
git commit -m "[S144.3] feat: sandbox provider abstraction"

Step 5: Distribute stashes to proper branches

# For each stashed session:
git checkout session-141
git stash pop   # or apply stash@{N}
git add -A && git commit -m "[S141.15] feat: cloudflare updater worker"

git checkout session-139
git stash pop
git add -A && git commit -m "[S139.6] test: A2A integration tests"

# Return to your session
git checkout session-144

7. Sub-Session Numbering Rules

How sub-sessions work

Rules for agents

  1. Always check the current sub-session before starting work:
    session({ action: "get_info" })
    
  2. Increment by 1 from the last known sub-session
  3. Never reuse a sub-session number — if 144.5 exists, use 144.6
  4. Never skip — don't jump from 144.3 to 144.7
  5. Set it explicitly when starting:
    session({ action: "set", sessionNumber: 144, subSessionNumber: 6 })
    

Multiple agents on the same session

If two agents need to work on the same session:


8. Quick Reference Card

Before ANY work

# 1. Set session in MCP
preflight({ task: "...", sessionNumber: N })

# 2. Verify lane (must relate to session N — including range lanes)
git branch --show-current
git checkout <lane>              # Switch if needed (session-{N} or session-{A}-{B}_*)
git checkout -b <lane>           # Create if new

After completing work

# 1. Stage and commit
git add <your-files>
git commit -m "[S{N}.{sub}] type: description"

# 2. Update MCP
log_decision({ ... })
outcome({ action: "report", ... })

Switching sessions

# 1. Stash current work
git stash push -m "S{N}.{sub}: WIP description"

# 2. Switch lane
git checkout <lane-for-other-session>

# 3. When returning
git checkout <your-lane>
git stash pop

Cleaning up mixed changes

# 1. Stash foreign files
git stash push -m "S{OTHER}: description" -- <foreign-files>

# 2. Commit your files on the current branch
git add <your-files> && git commit -m "[S{N}.{sub}] ..."

# 3. Leave foreign stashes for later — DO NOT checkout old branches here
#    The session owner or a dedicated cleanup pass will handle them

9. Crash Recovery Protocol

If an agent crashes mid-operation, the next agent MUST run this diagnostic before doing anything:

# 1. Where am I?
git branch --show-current

# 2. What's in the working tree?
git status --porcelain --untracked-files=no | wc -l   # tracked changes
git status --porcelain --untracked-files=no            # list them

# 3. What stashes exist?
git stash list

# 4. What was the last commit?
git log --oneline -3

# 5. Am I on the wrong lane? (common after crash)
#    If yes, checkout the correct lane for this session:
git checkout <lane>

Recovery Scenarios

Scenario A: Agent crashed during stash push

Scenario B: Agent crashed during branch checkout

Scenario C: Agent crashed during commit

Scenario D: Unknown state


10. Anti-Patterns (NEVER Do These)

Note: Section numbers 10-13 were renumbered in SAGP v1.2 to fix a duplicate §10. v1.3 adds concurrent lanes; §14 replaces the old integrate/* chapter.

Anti-Pattern Why It's Bad Do This Instead
Accumulate changes across sub-sessions without committing Creates the exact mess we're trying to avoid Commit after each sub-session
Work on main directly Blocks other agents, risks stable code Use a session-* lane (including range lanes)
Commit files from multiple sessions in one commit Makes rollback and tracking impossible One session per commit
Leave work in stashes permanently Stashes get lost and confusing Pop and commit within the same task
Skip preflight / session set MCP loses track of who's doing what Always init the session first
Reuse or skip sub-session numbers Breaks the session timeline Always increment by 1
Commit without [S{N}.{sub}] prefix Breaks traceability Always tag commits
Push to main without merging through a PR / policy Bypasses review, breaks history Open PR from session lane; tag merge per session-git-concurrent-lanes-spec.md
Checkout old branches in the live workspace IDE shows thousands of build artifacts as "changes", causes panic and potential mistakes Use cherry-pick or leave stashes for later
Run git add -A or git add . on an old branch Stages build artifacts and unrelated files Always git add <specific-files>
Perform multi-step git operations without a backup stash If agent crashes mid-operation, recovery is harder Always git stash push --include-untracked -m "BACKUP: ..." first

11. Merge Protocol — Converging Session Branches

When multiple session branches diverge, they need to converge. Follow this protocol:

When to merge

Situation Action
Session completed, tested, ready Merge session branch → main
Multiple session branches diverged from same base Merge older sessions INTO the most advanced branch
Need changes from another session git cherry-pick <commit> (do NOT merge the whole branch)

How to merge safely

# 1. Pre-flight check: will there be conflicts?
git diff --name-only session-144-new...session-141   # unique files only
git log --oneline session-141 -3                      # understand what's on it

# 2. If no overlapping files → merge directly:
git merge session-141 -m "merge: absorb S141 description into session-{N}"

# 3. If conflicts are expected → dry-run first:
git merge --no-commit --no-ff session-141
git diff --cached --stat                # review what will change
git merge --abort                       # cancel if unhappy
# OR: git commit -m "merge: ..."       # accept if clean

Merge commit message format

merge: absorb S{OTHER} {brief description} into session-{N}

Merge direction rules

  1. Older INTO newer — always merge the older/smaller branch into the most advanced one
  2. Never merge main into a session branch — rebase instead if needed
  3. Session branch → main — only when the session is fully complete and tested
  4. After merging, the absorbed branch can be deleted: git branch -d session-{OTHER}

Cherry-pick for surgical transfers

When you only need ONE commit from another branch (not the whole branch):

# Find the commit hash
git log --oneline session-141 -5

# Cherry-pick it onto your branch
git cherry-pick <commit-hash>

This avoids merge commits entirely and keeps history linear.


12. Stash Naming Convention

Format

S{session}.{sub}: {verb} {what} [{status}]

Status tags

Tag Meaning
WIP Work in progress, will return to this
READY Complete, ready to commit on target branch
ORPHAN Found on wrong branch, needs moving
BACKUP Safety snapshot, do not drop until verified

Examples

S144.3: WIP sandbox provider refactor
S141: READY cloudflare updater worker + tauri config
S139: ORPHAN A2A tests found on session-144
BACKUP: full working tree before SAGP cleanup - DO NOT DROP

Rules

  1. Stashes are TEMPORARY — never leave them longer than 1 session
  2. Always use -m — unnamed stashes are impossible to identify
  3. One concern per stash — don't mix unrelated files in a single stash
  4. Pop, don't apply — git stash pop removes the stash after applying; use apply only when you're uncertain
  5. Git does NOT support renaming stashes — if a stash has a bad name, pop it, then re-push with a better name

13. Session Types Reference

This workspace has three distinct session systems:

System ID Format Where Used By
Dev Sessions {workspace}-{N}.{sub} sessions/manifests/S{N}.json, MongoDB ai-agents.sessions MCP tools, agents, session-manager.js
Chat Sessions UUID MongoDB via backend-ai-api /sessions/* Frontend chat UI
Agent Sessions {userId}:{spaceId} MongoDB via backend-vitto-api Vitto agent conversations

This protocol applies to Dev Sessions only. Chat and Agent sessions are managed by their respective backends and don't interact with git.

Dev Session Data Flow

Agent calls preflight/set_session
  → MCP updates enforced session cache (process-scoped, 24h TTL)
  → MCP updates sessions/history.json (activeSessions[])
  → MCP syncs to MongoDB ai-agents.sessions (async)
  → Agent checks out a **lane** (`session-{N}` or a **range / shared** branch — see §2)
  → Agent works and commits with [S{N}.{sub}] tags
  → Agent calls log_decision + outcome
  → MCP records in manifest + MongoDB

14. Concurrent lanes & integrate/* (v1.3)

Concurrent lanes

Several sessions may share one Git branch (often a range lane like session-264-269_new). Ownership is always [S{N}.{sub}] per commit, not the branch name alone.

Normative spec: session-git-concurrent-lanes-spec.md

Merges to main

Use PRs (or your merge policy). PR titles and merge/squash messages must carry session traceability ([S{N}.{sub}] or an explicit session list). Details: concurrent-lanes spec §3.5–3.6.

Deprecated: integrate/{N}-{M} branches

The old disposable integrate/* workflow is deprecated in v1.3. Shared range lanes plus PR → main replace it. For a one-off local combine, use any temporary branch name—no integrate/* convention.

Legacy: Long-form integrate/* instructions were removed from this doc to avoid contradicting v1.3; recover from git history of this file prior to 2026-03-25 if needed.