Rename role to sandbox in layered sandbox config
- cfg/roles/ → cfg/sandbox/ - DefaultRole → DefaultSandbox, LoadRole → LoadSandbox - SessionOptions.Role → Sandbox, Session.Role() → Sandbox() - p9 file: role → sandbox - Remove tasks from layered sandbox config - Update create_session.sh and SKILL.md docs
This commit is contained in:
parent
c93bd19487
commit
d0e3ff2cd8
|
|
@ -107,5 +107,7 @@ env:
|
|||
- BITBUCKET_TOKEN
|
||||
- BITBUCKET_USERNAME
|
||||
- PCLOUD_USER
|
||||
- EDITOR
|
||||
- GIT_SEQUENCE_EDITOR
|
||||
network:
|
||||
unrestricted: true
|
||||
|
|
@ -15,10 +15,9 @@ var (
|
|||
|
||||
// SessionOptions contains options for creating a session
|
||||
type SessionOptions struct {
|
||||
CWD string
|
||||
Role string
|
||||
Tasks []string
|
||||
Model string // Optional model override (empty = backend default)
|
||||
CWD string
|
||||
Sandbox string
|
||||
Model string // Optional model override (empty = backend default)
|
||||
}
|
||||
|
||||
// Backend represents any chat backend (CLI tool via PTY, or direct API)
|
||||
|
|
@ -74,11 +73,8 @@ type Session interface {
|
|||
// SetAlias sets a user-friendly alias for the session
|
||||
SetAlias(alias string)
|
||||
|
||||
// Role returns the session role (empty if not specified)
|
||||
Role() string
|
||||
|
||||
// Tasks returns the session tasks (empty if not specified)
|
||||
Tasks() []string
|
||||
// Sandbox returns the session sandbox config (empty if not specified)
|
||||
Sandbox() string
|
||||
|
||||
// Model returns the active model override (empty = backend default)
|
||||
Model() string
|
||||
|
|
|
|||
|
|
@ -26,9 +26,8 @@ type Session struct {
|
|||
windowName string // window name within tmux session (same as id)
|
||||
cwd string
|
||||
alias string
|
||||
role string // session role (e.g., "developer", "reviewer")
|
||||
tasks []string // session tasks (e.g., ["git", "docker"])
|
||||
winID int // Acme window ID (0 if not applicable)
|
||||
sandbox string // sandbox config (e.g., "default", "restricted")
|
||||
winID int // Acme window ID (0 if not applicable)
|
||||
pid int
|
||||
state string
|
||||
context string // injected into first prompt only (consumed on first Send)
|
||||
|
|
@ -189,18 +188,11 @@ func (s *Session) Commands() backend.CommandHandler {
|
|||
return s.commands
|
||||
}
|
||||
|
||||
// Role returns the session role
|
||||
func (s *Session) Role() string {
|
||||
// Sandbox returns the session sandbox config
|
||||
func (s *Session) Sandbox() string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.role
|
||||
}
|
||||
|
||||
// Tasks returns the session tasks
|
||||
func (s *Session) Tasks() []string {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.tasks
|
||||
return s.sandbox
|
||||
}
|
||||
|
||||
// Model returns the active model override (empty = backend default)
|
||||
|
|
@ -670,7 +662,7 @@ func (s *Session) Restart(ctx context.Context) error {
|
|||
environment := s.environment
|
||||
backendName := s.backendName
|
||||
backendCommand := s.backendCommand
|
||||
role := s.role
|
||||
sbx := s.sandbox
|
||||
hadCrash := s.hadCrash
|
||||
model := s.model
|
||||
modelResolver := s.modelResolver
|
||||
|
|
@ -711,14 +703,14 @@ func (s *Session) Restart(ctx context.Context) error {
|
|||
}
|
||||
layers = append(layers, backendLayer)
|
||||
|
||||
if role == "" {
|
||||
role = sandbox.DefaultRole
|
||||
if sbx == "" {
|
||||
sbx = sandbox.DefaultSandbox
|
||||
}
|
||||
roleLayer, err := sandbox.LoadRole(role)
|
||||
sbxLayer, err := sandbox.LoadSandbox(sbx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load role %q: %w", role, err)
|
||||
return fmt.Errorf("failed to load sandbox %q: %w", sbx, err)
|
||||
}
|
||||
layers = append(layers, roleLayer)
|
||||
layers = append(layers, sbxLayer)
|
||||
|
||||
general := sandbox.GeneralConfig{BestEffort: false, LogLevel: "error"}
|
||||
advanced := sandbox.AdvancedConfig{LDD: false, AddExec: true}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ func (b *Backend) CreateSession(ctx context.Context, opts backend.SessionOptions
|
|||
id := generateID()
|
||||
windowName := id // Use session ID as window name
|
||||
|
||||
debug.Log("[session %s] creating window in tmux session %s (role=%s, tasks=%v)", id, b.tmuxSession, opts.Role, opts.Tasks)
|
||||
debug.Log("[session %s] creating window in tmux session %s (sandbox=%s)", id, b.tmuxSession, opts.Sandbox)
|
||||
|
||||
// Build layered sandbox configuration
|
||||
// Start with global.yaml as base
|
||||
|
|
@ -148,16 +148,16 @@ func (b *Backend) CreateSession(ctx context.Context, opts backend.SessionOptions
|
|||
}
|
||||
layers = append(layers, backendLayer)
|
||||
|
||||
// Add role layer if specified, otherwise use "default" role
|
||||
role := opts.Role
|
||||
if role == "" {
|
||||
role = sandbox.DefaultRole
|
||||
// Add sandbox layer if specified, otherwise use "default"
|
||||
sbx := opts.Sandbox
|
||||
if sbx == "" {
|
||||
sbx = sandbox.DefaultSandbox
|
||||
}
|
||||
roleLayer, err := sandbox.LoadRole(role)
|
||||
sbxLayer, err := sandbox.LoadSandbox(sbx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load role %q: %w", role, err)
|
||||
return nil, fmt.Errorf("failed to load sandbox %q: %w", sbx, err)
|
||||
}
|
||||
layers = append(layers, roleLayer)
|
||||
layers = append(layers, sbxLayer)
|
||||
|
||||
// Merge layers into final config
|
||||
general := sandbox.GeneralConfig{
|
||||
|
|
@ -348,8 +348,7 @@ func (b *Backend) CreateSession(ctx context.Context, opts backend.SessionOptions
|
|||
tmuxSession: b.tmuxSession,
|
||||
windowName: windowName,
|
||||
cwd: opts.CWD,
|
||||
role: role,
|
||||
tasks: opts.Tasks,
|
||||
sandbox: sbx,
|
||||
model: opts.Model,
|
||||
modelResolver: b.cfg.ModelResolver,
|
||||
pid: pid,
|
||||
|
|
|
|||
|
|
@ -105,15 +105,14 @@ const (
|
|||
fileAlias
|
||||
fileBackend
|
||||
fileContext
|
||||
fileRole
|
||||
fileTasks
|
||||
fileSandbox
|
||||
fileTmux
|
||||
fileMail
|
||||
fileModel
|
||||
fileCount
|
||||
)
|
||||
|
||||
var fileNames = []string{"ctl", "state", "pid", "cwd", "alias", "backend", "context", "role", "tasks", "tmux", "mail", "model"}
|
||||
var fileNames = []string{"ctl", "state", "pid", "cwd", "alias", "backend", "context", "sandbox", "tmux", "mail", "model"}
|
||||
|
||||
// Directory names in session
|
||||
var dirNames = []string{"inbox", "outbox", "completed"}
|
||||
|
|
@ -700,7 +699,7 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
if path == "/ctl" {
|
||||
args := strings.Fields(input)
|
||||
if len(args) < 2 || args[0] != "new" {
|
||||
return errFcall(fc, "usage: new <backend> <cwd> [role=<role>] [tasks=<task1,task2>]")
|
||||
return errFcall(fc, "usage: new <backend> <cwd> [sandbox=<sandbox>] [model=<model>]")
|
||||
}
|
||||
|
||||
backendName := args[1]
|
||||
|
|
@ -708,20 +707,15 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
if err != nil {
|
||||
return errFcall(fc, fmt.Sprintf("failed to get working directory: %v", err))
|
||||
}
|
||||
var role string
|
||||
var tasks []string
|
||||
var sbx string
|
||||
var model string
|
||||
|
||||
// Parse remaining arguments: first non-key=value is cwd, rest are options
|
||||
cwdSet := false
|
||||
for i := 2; i < len(args); i++ {
|
||||
arg := args[i]
|
||||
if r, ok := strings.CutPrefix(arg, "role="); ok {
|
||||
role = r
|
||||
} else if t, ok := strings.CutPrefix(arg, "tasks="); ok {
|
||||
if t != "" {
|
||||
tasks = strings.Split(t, ",")
|
||||
}
|
||||
if s, ok := strings.CutPrefix(arg, "sandbox="); ok {
|
||||
sbx = s
|
||||
} else if m, ok := strings.CutPrefix(arg, "model="); ok {
|
||||
model = m
|
||||
} else if !cwdSet {
|
||||
|
|
@ -753,10 +747,9 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
}
|
||||
|
||||
opts := backend.SessionOptions{
|
||||
CWD: cleanPath,
|
||||
Role: role,
|
||||
Tasks: tasks,
|
||||
Model: model,
|
||||
CWD: cleanPath,
|
||||
Sandbox: sbx,
|
||||
Model: model,
|
||||
}
|
||||
_, err = s.mgr.New(opts, backendName)
|
||||
if err != nil {
|
||||
|
|
@ -1550,10 +1543,8 @@ func (s *Server) getSessionFile(sess backend.Session, idx int) string {
|
|||
return tmuxSess.GetContext()
|
||||
}
|
||||
return ""
|
||||
case fileRole:
|
||||
return sess.Role()
|
||||
case fileTasks:
|
||||
return strings.Join(sess.Tasks(), ",")
|
||||
case fileSandbox:
|
||||
return sess.Sandbox()
|
||||
case fileTmux:
|
||||
tmuxSession, hasSession := meta.Extra["tmux_session"]
|
||||
tmuxWindow, hasWindow := meta.Extra["tmux_window"]
|
||||
|
|
|
|||
|
|
@ -176,8 +176,8 @@ func Save(cfg *Config) error {
|
|||
return os.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
||||
// DefaultRole is the role used when none is specified
|
||||
const DefaultRole = "default"
|
||||
// DefaultSandbox is the sandbox config used when none is specified
|
||||
const DefaultSandbox = "default"
|
||||
|
||||
// validateName checks if a role/task name is safe for use in file paths
|
||||
func validateName(name string) error {
|
||||
|
|
@ -344,18 +344,18 @@ func LoadBackend(name string) (LayeredConfig, error) {
|
|||
return cfg, nil
|
||||
}
|
||||
|
||||
// LoadRole loads role-specific config
|
||||
func LoadRole(name string) (LayeredConfig, error) {
|
||||
// LoadSandbox loads sandbox-specific config
|
||||
func LoadSandbox(name string) (LayeredConfig, error) {
|
||||
if err := validateName(name); err != nil {
|
||||
return LayeredConfig{}, fmt.Errorf("invalid role name: %w", err)
|
||||
return LayeredConfig{}, fmt.Errorf("invalid sandbox name: %w", err)
|
||||
}
|
||||
|
||||
home, _ := os.UserHomeDir()
|
||||
path := filepath.Join(home, ".config", "anvillm", "roles", name+".yaml")
|
||||
path := filepath.Join(home, ".config", "anvillm", "sandbox", name+".yaml")
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if os.IsNotExist(err) {
|
||||
return LayeredConfig{}, fmt.Errorf("role %q not found (looked in %s)", name, path)
|
||||
return LayeredConfig{}, fmt.Errorf("sandbox %q not found (looked in %s)", name, path)
|
||||
}
|
||||
if err != nil {
|
||||
return LayeredConfig{}, err
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# capabilities: agents
|
||||
# description: Create a new agent session
|
||||
# Usage: create_session.sh <backend> <cwd> [role=<role>] [tasks=<task1,task2>] [model=<model>]
|
||||
# Usage: create_session.sh <backend> <cwd> [sandbox=<sandbox>] [model=<model>]
|
||||
set -euo pipefail
|
||||
|
||||
if cat /etc/shadow >/dev/null 2>&1; then
|
||||
|
|
@ -10,7 +10,7 @@ if cat /etc/shadow >/dev/null 2>&1; then
|
|||
fi
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "usage: create_session.sh <backend> <cwd> [role=<role>] [tasks=<task1,task2>] [model=<model>]" >&2
|
||||
echo "usage: create_session.sh <backend> <cwd> [sandbox=<sandbox>] [model=<model>]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Create and control agent sessions.
|
|||
All commands must be run via `execute_code` tool:
|
||||
|
||||
- List sessions: `list_sessions.sh`
|
||||
- Create session: `create_session.sh <backend> <cwd> [role=<role>] [tasks=<task1,task2>] [model=<model>]`
|
||||
- Create session: `create_session.sh <backend> <cwd> [sandbox=<sandbox>] [model=<model>]`
|
||||
- Control session: `control_session.sh <session-id> <command>`
|
||||
- Spawn agent: `spawn_agent.sh <agent-id> [cwd-path] [initial-context-prompt]`
|
||||
- Kill agent: `kill_agent.sh [cwd-path]`
|
||||
|
|
@ -26,7 +26,7 @@ All commands must be run via `execute_code` tool:
|
|||
|
||||
## Session Lifecycle
|
||||
|
||||
1. Create: `create_session.sh kiro-cli /path/to/project role=developer`
|
||||
1. Create: `create_session.sh kiro-cli /path/to/project sandbox=default`
|
||||
2. Monitor: `list_sessions.sh` (check state field)
|
||||
3. Control: `control_session.sh <id> stop|restart|kill|refresh`
|
||||
|
||||
|
|
|
|||
Reference in New Issue