Session CLI Tools
Development guide for CLI tools that maintain context across invocations through session management.
Session CLI tools maintain context across multiple invocations without requiring a persistent background process. They save and restore a context identifier between calls via files, enabling multi-turn workflows.
Before reading this page, review the Common Standards that apply to all tool types.
Why Sessions are Needed
Some tools operate in multi-turn fashion — each invocation depends on the results and context of previous ones. Take agent_cursor (a CLI wrapper for Cursor IDE) as an example:
# Turn 1: Analyze the codebase
agent_cursor run "Analyze this project's architecture" --session main
# Cursor returns analysis results and produces a session_id
# Turn 2: Continue based on the analysis
agent_cursor run "Based on the previous analysis, refactor the auth module" --session main
# Automatically resumes the previous session_id — Cursor knows what "previous analysis" means
Without Sessions, the second invocation would have no idea what "the previous analysis" refers to, and the user would need to manually manage session_ids and pass --resume parameters. Session aliases automate this entirely.
The key difference from Daemon: Sessions don't require a persistent background process. The tool still follows "run and exit" — it just saves and restores a context identifier between invocations via files.
Architecture Overview
First invocation:
┌─────────┐ Args ┌───────────┐ Result + session_id ┌──────────────┐
│ Caller │ ──────► │ CLI Tool │ ──────────────────► │ Output │
│ │ │ │ │ │
└─────────┘ └─────┬─────┘ └──────────────┘
│ Save
▼
~/.tool/sessions/main.json
Subsequent invocations:
┌─────────┐ Args ┌───────────┐ Result ┌──────────────┐
│ Caller │ ──────► │ CLI Tool │ ──────► │ Output │
│ │ │ Auto- │ │ │
│ │ │ resume │ │ │
└─────────┘ └─────┬─────┘ └──────────────┘
│ Read
▲
~/.tool/sessions/main.json
Project Structure
agent_cursor/
├── main.go
├── go.mod
├── cmd/
│ ├── root.go # Root command, global --session flag
│ ├── skill.go # skillSpec constant
│ ├── run.go # Execute command (auto-resume)
│ └── session.go # session ls / show / rm subcommands
└── internal/
├── output/
│ └── output.go
└── session/
└── session.go # Session persistence logic
Session Data Structure
type SessionData struct {
Name string `json:"name"`
SessionID string `json:"sessionId"`
CWD string `json:"cwd"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
Session files are stored at ~/.agent_cursor/sessions/<name>.json, where the filename is the session alias.
Global --session Flag
Registered via PersistentFlags so all subcommands can use Sessions:
func init() {
rootCmd.PersistentFlags().StringVarP(&sessionName, "session", "s", "",
"Session alias name for automatic resume")
rootCmd.PersistentFlags().StringVar(&cwdPath, "cwd", "",
"Working directory for Cursor agent (default: current directory)")
}
Automatic Session Resumption
Automatically check and resume sessions during command execution — users don't need to know session_ids exist:
if sessionName != "" && resumeID == "" {
sess, err := session.Load(sessionName)
if err == nil && sess.SessionID != "" {
effectiveResumeID = sess.SessionID
}
}
// Save session after execution
if sessionName != "" && result.SessionID != "" {
session.Save(sessionName, result.SessionID, cwd)
}
Session Subcommands
Provide a session subcommand group for managing existing sessions:
agent_cursor session ls # List all sessions
agent_cursor session show <name> # View session details (session_id, creation time, etc.)
agent_cursor session rm <name> # Delete a session
Development Checklist
- All basic requirements from Common Standards
- Global
--sessionflag - Session data persisted to files (
~/.tool/sessions/) - Automatic session resumption during command execution
- Automatic session saving after command execution
-
session ls/session show/session rmmanagement subcommands -
--skilldocuments session usage and multi-turn interaction workflows