Skip to content

Commit e363e29

Browse files
feat(cli): rename "lk agent session" command to "daemon"
Address review feedback (theomonnom): the user-facing top-level command is now `lk agent daemon {start,say,stop}`. The hidden internal re-exec entrypoint that `start` launches is renamed `daemon` -> `run` to avoid the awkward `daemon daemon` path, so `start` now re-execs `lk agent daemon run`. Updates all user-facing strings, the e2e test invocations, the session-e2e workflow header, and regenerates fish completions. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 345a947 commit e363e29

7 files changed

Lines changed: 61 additions & 61 deletions

File tree

.github/workflows/session-e2e.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Session E2E
22

3-
# Drives the real `lk agent session` start/say/stop lifecycle against the minimal
3+
# Drives the real `lk agent daemon` start/say/stop lifecycle against the minimal
44
# one-file echo agent in cmd/lk/testdata/echo-agent, on Linux, macOS, and
55
# Windows. This exercises the detached daemon, the readiness handshake, the
66
# console IPC transport, and the model round-trip end to end -- runtime behavior

autocomplete/fish_autocomplete

Lines changed: 38 additions & 38 deletions
Large diffs are not rendered by default.

cmd/lk/agent_utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func detectProject(cmd *cli.Command) (string, agentfs.ProjectType, string, error
6868
}
6969

7070
// buildConsoleArgs builds the agent subprocess argv for console mode, shared by
71-
// `lk agent console` and the `lk agent session` daemon.
71+
// `lk agent console` and the `lk agent daemon` daemon.
7272
func buildConsoleArgs(addr string, record bool) []string {
7373
args := []string{"console", "--connect-addr", addr}
7474
if record {

cmd/lk/session.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const (
4545
envSessionReadyFile = "LK_SESSION_READY_FILE" // path the daemon writes its status to
4646

4747
// sessionDaemonSubcommand is the hidden entrypoint `start` re-execs into.
48-
sessionDaemonSubcommand = "daemon"
48+
sessionDaemonSubcommand = "run"
4949
)
5050

5151
var sessionPortFlag = &cli.IntFlag{
@@ -56,15 +56,15 @@ var sessionPortFlag = &cli.IntFlag{
5656
}
5757

5858
func init() {
59-
// Register under the `agent` group as `lk agent session`, mirroring how
59+
// Register under the `agent` group as `lk agent daemon`, mirroring how
6060
// `lk agent console` attaches itself. Unlike console, this command is not
6161
// gated behind the `console` build tag: it is CGO-free and ships in the
6262
// default binary.
63-
AgentCommands[0].Commands = append(AgentCommands[0].Commands, agentSessionCommand)
63+
AgentCommands[0].Commands = append(AgentCommands[0].Commands, agentDaemonCommand)
6464
}
6565

66-
var agentSessionCommand = &cli.Command{
67-
Name: "session",
66+
var agentDaemonCommand = &cli.Command{
67+
Name: "daemon",
6868
Usage: "Drive a single local agent session in text mode (start/say/stop)",
6969
Category: "Core",
7070
Commands: []*cli.Command{
@@ -93,7 +93,7 @@ var agentSessionCommand = &cli.Command{
9393
Hidden: true,
9494
Action: func(ctx context.Context, cmd *cli.Command) error {
9595
if os.Getenv(envSessionReadyFile) == "" {
96-
return fmt.Errorf("`session daemon` is an internal entrypoint; run `lk agent session start <entrypoint>` instead")
96+
return fmt.Errorf("`lk agent daemon run` is an internal entrypoint; run `lk agent daemon start <entrypoint>` instead")
9797
}
9898
runSessionDaemon()
9999
return nil
@@ -135,7 +135,7 @@ func runSessionStart(ctx context.Context, cmd *cli.Command) error {
135135
return err
136136
}
137137

138-
daemon := exec.Command(exe, "agent", "session", sessionDaemonSubcommand)
138+
daemon := exec.Command(exe, "agent", "daemon", sessionDaemonSubcommand)
139139
daemon.Env = append(os.Environ(),
140140
envSessionPort+"="+strconv.Itoa(port),
141141
envSessionDir+"="+projectDir,
@@ -157,7 +157,7 @@ func runSessionStart(ctx context.Context, cmd *cli.Command) error {
157157
switch {
158158
case status == "ready":
159159
fmt.Fprintf(os.Stderr, "Detected %s agent (%s in %s)\n", projectType.Lang(), entrypoint, projectDir)
160-
fmt.Printf("Session started. Use `lk agent session say \"...\"` to talk, `lk agent session stop` to stop.\n")
160+
fmt.Printf("Session started. Use `lk agent daemon say \"...\"` to talk, `lk agent daemon stop` to stop.\n")
161161
return nil
162162
case strings.HasPrefix(status, "error:"):
163163
return fmt.Errorf("%s", strings.TrimSpace(strings.TrimPrefix(status, "error:")))
@@ -206,7 +206,7 @@ func readReadyStatus(path string) (string, bool) {
206206
func runSessionSay(ctx context.Context, cmd *cli.Command) error {
207207
text := strings.TrimSpace(strings.Join(cmd.Args().Slice(), " "))
208208
if text == "" {
209-
return fmt.Errorf("usage: lk agent session say <text>")
209+
return fmt.Errorf("usage: lk agent daemon say <text>")
210210
}
211211
conn, err := dialControl(int(cmd.Int("port")))
212212
if err != nil {
@@ -241,7 +241,7 @@ func runSessionStop(ctx context.Context, cmd *cli.Command) error {
241241
func dialControl(port int) (net.Conn, error) {
242242
conn, err := net.Dial("tcp", sessionAddr(port))
243243
if err != nil {
244-
return nil, fmt.Errorf("no session running on %s (run `lk agent session start` first)", sessionAddr(port))
244+
return nil, fmt.Errorf("no session running on %s (run `lk agent daemon start` first)", sessionAddr(port))
245245
}
246246
if _, err := conn.Write([]byte(sessionMagic)); err != nil {
247247
conn.Close()

cmd/lk/session_daemon.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ import (
3131
agent "github.com/livekit/protocol/livekit/agent"
3232
)
3333

34-
// runSessionDaemon is the entry point for the hidden `lk agent session daemon`
35-
// subcommand that `lk agent session start` re-execs. It runs the detached
34+
// runSessionDaemon is the entry point for the hidden `lk agent daemon run`
35+
// subcommand that `lk agent daemon start` re-execs. It runs the detached
3636
// daemon to completion (until the agent exits or `stop` is received).
3737
func runSessionDaemon() {
3838
ready := readyWriter()
3939
port, _ := strconv.Atoi(os.Getenv(envSessionPort))
4040

4141
// The fixed port is the singleton: if the bind fails, a session already
42-
// owns it, which is how `lk agent session start` learns to reject.
42+
// owns it, which is how `lk agent daemon start` learns to reject.
4343
server, err := console.NewTCPServer(sessionAddr(port))
4444
if err != nil {
4545
signalReady(ready, "error: a session is already running on "+sessionAddr(port))
@@ -100,7 +100,7 @@ func runSessionDaemon() {
100100
agentProc.Kill()
101101
}
102102

103-
// readyWriter returns the path of the readiness file `lk agent session start`
103+
// readyWriter returns the path of the readiness file `lk agent daemon start`
104104
// polls to learn the daemon became ready (or failed). Empty if not launched
105105
// via start.
106106
func readyWriter() string {

cmd/lk/session_e2e_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
const sessionE2ETimeout = 5 * time.Second
3333

34-
// TestSessionE2E drives the real `lk agent session` lifecycle end to end:
34+
// TestSessionE2E drives the real `lk agent daemon` lifecycle end to end:
3535
// build the binary, `start` the detached daemon, `say` to make the model echo
3636
// a token (asserting the CLI→daemon→agent→LLM round-trip), `stop`, confirm a
3737
// second `say` cannot still reach the agent, then confirm the daemon exited
@@ -99,24 +99,24 @@ func TestSessionE2E(t *testing.T) {
9999

100100
// Best-effort teardown so a mid-run failure doesn't leave the daemon alive.
101101
t.Cleanup(func() {
102-
_, _ = run(sessionE2ETimeout, "agent", "session", "stop", "--port", port)
102+
_, _ = run(sessionE2ETimeout, "agent", "daemon", "stop", "--port", port)
103103
})
104104

105105
// start: launches the detached daemon and returns once the agent is ready.
106-
startOut, err := run(15*time.Second, "agent", "session", "start", "--port", port, entrypoint)
106+
startOut, err := run(15*time.Second, "agent", "daemon", "start", "--port", port, entrypoint)
107107
require.NoError(t, err, "session start failed:\n%s", startOut)
108108
require.Contains(t, startOut, "Session started.", "start did not report readiness:\n%s", startOut)
109109

110110
// say: the token appears once in the echoed prompt and again in the reply, so
111111
// >=2 occurrences proves the agent answered, not just the local echo.
112112
token := "PINEAPPLE7351"
113-
sayOut, err := run(sessionE2ETimeout, "agent", "session", "say", "--port", port,
113+
sayOut, err := run(sessionE2ETimeout, "agent", "daemon", "say", "--port", port,
114114
"Repeat this token back to me exactly and nothing else: "+token)
115115
require.NoError(t, err, "session say failed:\n%s", sayOut)
116116
require.GreaterOrEqualf(t, strings.Count(sayOut, token), 2,
117117
"agent did not echo the token back; say output:\n%s", sayOut)
118118

119-
stopOut, err := run(sessionE2ETimeout, "agent", "session", "stop", "--port", port)
119+
stopOut, err := run(sessionE2ETimeout, "agent", "daemon", "stop", "--port", port)
120120
require.NoError(t, err, "session stop failed:\n%s", stopOut)
121121
require.Contains(t, stopOut, "Session ended.", "stop did not confirm shutdown:\n%s", stopOut)
122122

@@ -125,7 +125,7 @@ func TestSessionE2E(t *testing.T) {
125125

126126
// After a successful match and shutdown, another say must not reach a live
127127
// agent or reproduce the token.
128-
afterStopSay, err := runCapture(sessionE2ETimeout, "agent", "session", "say", "--port", port,
128+
afterStopSay, err := runCapture(sessionE2ETimeout, "agent", "daemon", "say", "--port", port,
129129
"Repeat this token back to me exactly and nothing else: "+token)
130130
afterStopSayOut := afterStopSay.stdout + afterStopSay.stderr
131131
require.Error(t, err, "session say unexpectedly succeeded after stop:\n%s", afterStopSayOut)

cmd/lk/testdata/echo-agent/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Minimal one-file echo agent for the `lk agent session` e2e test.
1+
"""Minimal one-file echo agent for the `lk agent daemon` e2e test.
22
33
Driven in text mode, so an LLM is the only component needed. Echoes the user's
44
text verbatim, which the test asserts on.

0 commit comments

Comments
 (0)