| layout | default |
|---|---|
| title | Chapter 6: Multi-IDE Adaptation (Codex, Gemini, OpenCode, Cursor) |
| nav_order | 6 |
| parent | Planning with Files Tutorial |
Welcome to Chapter 6: Multi-IDE Adaptation (Codex, Gemini, OpenCode, Cursor). In this part of Planning with Files Tutorial: Persistent Markdown Workflow Memory for AI Coding Agents, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.
This chapter shows how to carry one planning workflow across multiple coding-agent environments.
- map equivalent skill installation paths across IDEs
- align command usage and behavior where syntax differs
- keep team onboarding docs consistent across tools
- avoid path/version drift in mixed environments
- define one canonical workflow contract (files + cadence)
- map runtime-specific install/invocation syntax
- run cross-tool smoke tests on small tasks
You now have a practical strategy for multi-IDE workflow consistency.
Next: Chapter 7: Troubleshooting, Anti-Patterns, and Safety Checks
The get_project_dir function in .continue/skills/planning-with-files/scripts/session-catchup.py handles a key part of this chapter's functionality:
def get_project_dir(project_path: str) -> Tuple[Optional[Path], Optional[str]]:
"""Resolve session storage path for the current runtime variant."""
normalized = normalize_path(project_path)
# Claude Code's sanitization: replace path separators and : with -
sanitized = normalized.replace('\\', '-').replace('/', '-').replace(':', '-')
sanitized = sanitized.replace('_', '-')
# Strip leading dash if present (Unix absolute paths start with /)
if sanitized.startswith('-'):
sanitized = sanitized[1:]
claude_path = Path.home() / '.claude' / 'projects' / sanitized
# Codex stores sessions in ~/.codex/sessions with a different format.
# Avoid silently scanning Claude paths when running from Codex skill folder.
script_path = Path(__file__).as_posix().lower()
is_codex_variant = '/.codex/' in script_path
codex_sessions_dir = Path.home() / '.codex' / 'sessions'
if is_codex_variant and codex_sessions_dir.exists() and not claude_path.exists():
return None, (
"[planning-with-files] Session catchup skipped: Codex stores sessions "
"in ~/.codex/sessions and native Codex parsing is not implemented yet."
)
return claude_path, None
def get_sessions_sorted(project_dir: Path) -> List[Path]:
"""Get all session files sorted by modification time (newest first)."""
sessions = list(project_dir.glob('*.jsonl'))This function is important because it defines how Planning with Files Tutorial: Persistent Markdown Workflow Memory for AI Coding Agents implements the patterns covered in this chapter.
The get_sessions_sorted function in .continue/skills/planning-with-files/scripts/session-catchup.py handles a key part of this chapter's functionality:
def get_sessions_sorted(project_dir: Path) -> List[Path]:
"""Get all session files sorted by modification time (newest first)."""
sessions = list(project_dir.glob('*.jsonl'))
main_sessions = [s for s in sessions if not s.name.startswith('agent-')]
return sorted(main_sessions, key=lambda p: p.stat().st_mtime, reverse=True)
def parse_session_messages(session_file: Path) -> List[Dict]:
"""Parse all messages from a session file, preserving order."""
messages = []
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
data['_line_num'] = line_num
messages.append(data)
except json.JSONDecodeError:
pass
return messages
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
"""
Find the last time a planning file was written/edited.
Returns (line_number, filename) or (-1, None) if not found.
"""
last_update_line = -1
last_update_file = None
for msg in messages:This function is important because it defines how Planning with Files Tutorial: Persistent Markdown Workflow Memory for AI Coding Agents implements the patterns covered in this chapter.
The parse_session_messages function in .continue/skills/planning-with-files/scripts/session-catchup.py handles a key part of this chapter's functionality:
def parse_session_messages(session_file: Path) -> List[Dict]:
"""Parse all messages from a session file, preserving order."""
messages = []
with open(session_file, 'r', encoding='utf-8', errors='replace') as f:
for line_num, line in enumerate(f):
try:
data = json.loads(line)
data['_line_num'] = line_num
messages.append(data)
except json.JSONDecodeError:
pass
return messages
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
"""
Find the last time a planning file was written/edited.
Returns (line_number, filename) or (-1, None) if not found.
"""
last_update_line = -1
last_update_file = None
for msg in messages:
msg_type = msg.get('type')
if msg_type == 'assistant':
content = msg.get('message', {}).get('content', [])
if isinstance(content, list):
for item in content:
if item.get('type') == 'tool_use':This function is important because it defines how Planning with Files Tutorial: Persistent Markdown Workflow Memory for AI Coding Agents implements the patterns covered in this chapter.
The find_last_planning_update function in .continue/skills/planning-with-files/scripts/session-catchup.py handles a key part of this chapter's functionality:
def find_last_planning_update(messages: List[Dict]) -> Tuple[int, Optional[str]]:
"""
Find the last time a planning file was written/edited.
Returns (line_number, filename) or (-1, None) if not found.
"""
last_update_line = -1
last_update_file = None
for msg in messages:
msg_type = msg.get('type')
if msg_type == 'assistant':
content = msg.get('message', {}).get('content', [])
if isinstance(content, list):
for item in content:
if item.get('type') == 'tool_use':
tool_name = item.get('name', '')
tool_input = item.get('input', {})
if tool_name in ('Write', 'Edit'):
file_path = tool_input.get('file_path', '')
for pf in PLANNING_FILES:
if file_path.endswith(pf):
last_update_line = msg['_line_num']
last_update_file = pf
return last_update_line, last_update_file
def extract_messages_after(messages: List[Dict], after_line: int) -> List[Dict]:This function is important because it defines how Planning with Files Tutorial: Persistent Markdown Workflow Memory for AI Coding Agents implements the patterns covered in this chapter.
flowchart TD
A[get_project_dir]
B[get_sessions_sorted]
C[parse_session_messages]
D[find_last_planning_update]
E[extract_messages_after]
A --> B
B --> C
C --> D
D --> E