Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ shelli provides persistent interactive shell sessions via PTY-backed processes m
- `storage_memory.go`: In-memory storage with circular buffer (default, 10MB limit)
- `storage_file.go`: File-based persistent storage
- `constants.go`: Shared constants (buffer sizes, timeouts)
- Socket at `~/.shelli/shelli.sock`, auto-started on first command
- Socket at `/tmp/shelli-{uid}/shelli.sock`, auto-started on first command

**MCP Server** (`internal/mcp/`)
- `server.go`: JSON-RPC stdio server implementing MCP protocol
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,10 @@ Sessions have explicit states with clear transitions:

## Storage

By default, shelli stores session output in files at `~/.shelli/data/`:
By default, shelli stores session output in files at `/tmp/shelli-{uid}/data/`:

```
~/.shelli/data/
/tmp/shelli-{uid}/data/
├── mysession.out # raw PTY output (0600 permissions)
└── mysession.meta # JSON metadata (state, pid, timestamps)
```
Expand All @@ -379,15 +379,15 @@ shelli daemon [flags]

| Flag | Default | Description |
|------|---------|-------------|
| `--data-dir` | `~/.shelli/data` | Directory for session files |
| `--data-dir` | `/tmp/shelli-{uid}/data` | Directory for session files |
| `--memory-backend` | `false` | Use in-memory storage (no persistence) |
| `--stopped-ttl` | (disabled) | Auto-delete stopped sessions after duration |
| `--max-output` | `10MB` | Buffer size limit (memory backend only) |

Examples:
```bash
# Use custom storage location
shelli daemon --data-dir ~/.shelli/sessions
shelli daemon --data-dir /tmp/shelli-sessions

# Memory-only mode (v0.3 behavior)
shelli daemon --memory-backend --max-output 50MB
Expand Down Expand Up @@ -454,7 +454,7 @@ shelli uses a daemon process to maintain PTY handles across CLI invocations:
│ │
│ ┌────────────────────┐ ┌────────────────────────────────┐ │
│ │ MCP Server │ │ Socket Server │ │
│ │ (--mcp flag) │ │ (~/.shelli/shelli.sock) │ │
│ │ (--mcp flag) │ │ (/tmp/shelli-{uid}/shelli.sock)│ │
│ └─────────┬──────────┘ └─────────────┬──────────────────┘ │
│ └───────────┬───────────────────┘ │
│ ▼ │
Expand Down
8 changes: 4 additions & 4 deletions cmd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func init() {
daemonCmd.Flags().BoolVar(&daemonMCPFlag, "mcp", false,
"Run as MCP server (JSON-RPC over stdio)")
daemonCmd.Flags().StringVar(&daemonDataDirFlag, "data-dir", "",
"Directory for session output files (default: ~/.shelli/data)")
"Directory for session output files (default: /tmp/shelli-{uid}/data)")
daemonCmd.Flags().BoolVar(&daemonMemoryBackend, "memory-backend", false,
"Use in-memory storage instead of file-based (no persistence)")
daemonCmd.Flags().StringVar(&daemonStoppedTTLFlag, "stopped-ttl", "",
Expand Down Expand Up @@ -68,11 +68,11 @@ func runDaemon(cmd *cobra.Command, args []string) error {
var opts []daemon.ServerOption

if daemonDataDirFlag == "" {
homeDir, err := os.UserHomeDir()
runtimeDir, err := daemon.RuntimeDir()
if err != nil {
return fmt.Errorf("get home dir: %w", err)
return fmt.Errorf("get runtime dir: %w", err)
}
daemonDataDirFlag = filepath.Join(homeDir, ".shelli", "data")
daemonDataDirFlag = filepath.Join(runtimeDir, "data")
}

if daemonMemoryBackend {
Expand Down
18 changes: 10 additions & 8 deletions internal/daemon/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,22 @@ func WithMaxOutputSize(size int) ServerOption {
}
}

func RuntimeDir() (string, error) {
return filepath.Join(os.TempDir(), fmt.Sprintf("shelli-%d", os.Getuid())), nil
}

func NewServer(opts ...ServerOption) (*Server, error) {
homeDir, err := os.UserHomeDir()
runtimeDir, err := RuntimeDir()
if err != nil {
return nil, err
}

socketDir := filepath.Join(homeDir, ".shelli")
if err := os.MkdirAll(socketDir, 0700); err != nil {
if err := os.MkdirAll(runtimeDir, 0700); err != nil {
return nil, err
}

s := &Server{
handles: make(map[string]*sessionHandle),
socketDir: socketDir,
socketDir: runtimeDir,
storage: NewMemoryStorage(DefaultMaxOutputSize),
cleanupStopChan: make(chan struct{}),
}
Expand Down Expand Up @@ -161,11 +163,11 @@ func (s *Server) recoverSessions() error {
}

func SocketPath() (string, error) {
homeDir, err := os.UserHomeDir()
runtimeDir, err := RuntimeDir()
if err != nil {
return "", fmt.Errorf("get home dir: %w", err)
return "", err
}
return filepath.Join(homeDir, ".shelli", "shelli.sock"), nil
return filepath.Join(runtimeDir, "shelli.sock"), nil
}

func (s *Server) socketPath() string {
Expand Down