Skip to main content
Glama
xiaolai

claude-octopus

claude_code_timeline

Query cross-agent workflow timelines. List all runs with no arguments, view agent sequence for a specific run, or retrieve timeline entries and session metadata by session ID.

Instructions

Query the cross-agent workflow timeline. No args: list all runs. run_id: show one run's agent sequence. session_id: retrieve timeline entry and session metadata. Use claude_code_transcript for full transcripts.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
run_idNoShow all entries for this workflow run, ordered by time
session_idNoRetrieve timeline entry and session metadata for a specific session

Implementation Reference

  • src/index.ts:47-48 (registration)
    Registration: The timeline tool name is derived as `${TOOL_NAME}_timeline`. When TOOL_NAME defaults to 'claude_code', the tool becomes 'claude_code_timeline'.
    const TIMELINE_TOOL_NAME = `${TOOL_NAME}_timeline`;
    const SERVER_NAME = envStr("CLAUDE_SERVER_NAME") || "claude-octopus";
  • src/index.ts:71-76 (registration)
    Registration: registerTimelineTool() is called with TOOL_NAME (default 'claude_code'), which internally creates the tool name `${toolName}_timeline` = 'claude_code_timeline'.
    registerTimelineTool(
      server,
      TOOL_NAME,
      CONFIG.timeline,
      CONFIG.sdkOptions.persistSession !== false,
    );
  • Handler: registerTimelineTool() registers the 'claude_code_timeline' MCP tool. It accepts optional run_id and session_id inputs, reads from the timeline JSONL index, and returns entries — listing all runs (no args), filtering by run_id, or looking up a specific session_id.
    export function registerTimelineTool(
      server: McpServer,
      toolName: string,
      timelineConfig: TimelineConfig,
      persistSession: boolean,
    ) {
      const timelineToolName = `${toolName}_timeline`;
    
      server.registerTool(timelineToolName, {
        description: [
          "Query the cross-agent workflow timeline.",
          "No args: list all runs. run_id: show one run's agent sequence.",
          persistSession
            ? `session_id: retrieve timeline entry and session metadata. Use ${toolName}_transcript for full transcripts.`
            : "session_id: retrieve entry metadata (transcripts unavailable — session persistence is off).",
        ].join(" "),
        inputSchema: z.object({
          run_id: z.string().optional().describe("Show all entries for this workflow run, ordered by time"),
          session_id: z.string().optional().describe("Retrieve timeline entry and session metadata for a specific session"),
        }),
      }, async ({ run_id, session_id }) => {
        try {
          // Mode 1: specific session
          if (session_id) {
            // Always return the timeline entry for this session
            const entries = await readTimeline(timelineConfig.dir, { sessionId: session_id });
            const entryData = entries.length > 0
              ? entries[0]
              : null;
    
            if (persistSession) {
              // Try to get session info from Claude Code's storage
              const info = await getSessionInfo(session_id).catch(() => undefined);
              return {
                content: [{
                  type: "text" as const,
                  text: JSON.stringify({
                    timeline_entry: entryData,
                    session_info: info || null,
                  }, null, 2),
                }],
              };
            }
    
            return {
              content: [{
                type: "text" as const,
                text: JSON.stringify({
                  timeline_entry: entryData,
                  session_info: null,
                  note: "Session persistence is off — full transcripts unavailable.",
                }, null, 2),
              }],
            };
          }
    
          // Mode 2: specific run
          if (run_id) {
            const entries = await readTimeline(timelineConfig.dir, { runId: run_id });
            return {
              content: [{
                type: "text" as const,
                text: JSON.stringify({ run_id, entries }, null, 2),
              }],
            };
          }
    
          // Mode 3: list all runs
          const runs = await listRuns(timelineConfig.dir);
          return {
            content: [{
              type: "text" as const,
              text: JSON.stringify({ runs }, null, 2),
            }],
          };
        } catch (error) {
          return {
            content: [{
              type: "text" as const,
              text: `Error reading timeline: ${error instanceof Error ? error.message : String(error)}`,
            }],
            isError: true,
          };
        }
      });
    
      // Separate tool for full transcript retrieval — only when persistence is on
      if (persistSession) {
        server.registerTool(`${toolName}_transcript`, {
          description: [
            `Retrieve the full conversation transcript for a session from Claude Code's storage.`,
            "Returns chronological user/assistant messages. Use session_id from a prior query or timeline lookup.",
          ].join(" "),
          inputSchema: z.object({
            session_id: z.string().describe("Session ID to retrieve transcript for"),
            limit: z.number().int().positive().optional().describe("Maximum number of messages to return"),
            offset: z.number().int().optional().describe("Skip this many messages from the start"),
            include_system: z.boolean().optional().describe("Include system messages (default: false)"),
          }),
        }, async ({ session_id, limit, offset, include_system }) => {
          try {
            const messages = await getSessionMessages(session_id, {
              limit,
              offset,
              includeSystemMessages: include_system,
            });
            return {
              content: [{
                type: "text" as const,
                text: JSON.stringify({
                  session_id,
                  message_count: messages.length,
                  messages,
                }, null, 2),
              }],
            };
          } catch (error) {
            return {
              content: [{
                type: "text" as const,
                text: `Error retrieving transcript: ${error instanceof Error ? error.message : String(error)}`,
              }],
              isError: true,
            };
          }
        });
      }
  • Schema: The input schema defines two optional fields — run_id and session_id — both as zod strings.
    inputSchema: z.object({
      run_id: z.string().optional().describe("Show all entries for this workflow run, ordered by time"),
      session_id: z.string().optional().describe("Retrieve timeline entry and session metadata for a specific session"),
    }),
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided. Description does not explicitly state whether the tool is read-only, destructive, or any auth requirements. It implies read-only behavior by describing queries, but doesn't guarantee it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences that front-load the purpose and action, with no unnecessary words. Every part adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema; description does not specify the format of returned data (e.g., fields in timeline entries). Lacks details on pagination, limits, or error handling, but sufficient for basic use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with parameter descriptions. The description adds some context (e.g., 'agent sequence' for run_id) but does not significantly improve understanding beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Query the cross-agent workflow timeline' which is a specific verb and resource. It distinguishes from sibling tools like claude_code_transcript which handles full transcripts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance on when to use each argument: 'No args: list all runs. run_id: show one run's agent sequence. session_id: retrieve timeline entry and session metadata.' Also directs to alternative tool: 'Use claude_code_transcript for full transcripts.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/xiaolai/claude-octopus'

If you have feedback or need assistance with the MCP directory API, please join our Discord server