Chapter 1: Getting Started
April 13, 2026 ยท View on GitHub
Welcome to Chapter 1: Getting Started. In this part of gptme Tutorial: Open-Source Terminal Agent for Local Tool-Driven Work, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.
This chapter gets gptme installed and running in a local terminal session.
Quick Install
pipx install gptme
# or
uv tool install gptme
First Run
gptme
If provider keys are missing, gptme prompts to configure them.
Source References
Summary
You now have gptme installed and ready for interactive local workflows.
Next: Chapter 2: Core CLI Workflow and Prompt Patterns
Source Code Walkthrough
gptme/codeblock.py
The Codeblock class in gptme/codeblock.py handles a key part of this chapter's functionality:
@dataclass(frozen=True)
class Codeblock:
lang: str
content: str
path: str | None = None
start: int | None = field(default=None, compare=False)
fence: str = field(default_factory=lambda: "```", compare=False, repr=False)
def __post_init__(self):
# init path if path is None and lang is pathy
if self.path is None and self.is_filename:
object.__setattr__(self, "path", self.lang) # frozen dataclass workaround
def to_markdown(self) -> str:
return f"{self.fence}{self.lang}\n{self.content}\n{self.fence}"
def to_xml(self) -> str:
"""Converts codeblock to XML with proper escaping."""
# Use quoteattr for attributes to handle quotes and special chars safely
# Use xml_escape for content to handle <, >, & characters
path_attr = f" path={quoteattr(self.path)}" if self.path else ""
return f"<codeblock lang={quoteattr(self.lang)}{path_attr}>\n{xml_escape(self.content)}\n</codeblock>"
@classmethod
@trace_function(name="codeblock.from_markdown", attributes={"component": "parser"})
def from_markdown(cls, content: str) -> "Codeblock":
stripped = content.strip()
fence_len = 0
# Handle variable-length fences (3+ backticks)
start_match = re.match(r"^(`{3,})", stripped)
This class is important because it defines how gptme Tutorial: Open-Source Terminal Agent for Local Tool-Driven Work implements the patterns covered in this chapter.
gptme/codeblock.py
The workaround class in gptme/codeblock.py handles a key part of this chapter's functionality:
# init path if path is None and lang is pathy
if self.path is None and self.is_filename:
object.__setattr__(self, "path", self.lang) # frozen dataclass workaround
def to_markdown(self) -> str:
return f"{self.fence}{self.lang}\n{self.content}\n{self.fence}"
def to_xml(self) -> str:
"""Converts codeblock to XML with proper escaping."""
# Use quoteattr for attributes to handle quotes and special chars safely
# Use xml_escape for content to handle <, >, & characters
path_attr = f" path={quoteattr(self.path)}" if self.path else ""
return f"<codeblock lang={quoteattr(self.lang)}{path_attr}>\n{xml_escape(self.content)}\n</codeblock>"
@classmethod
@trace_function(name="codeblock.from_markdown", attributes={"component": "parser"})
def from_markdown(cls, content: str) -> "Codeblock":
stripped = content.strip()
fence_len = 0
# Handle variable-length fences (3+ backticks)
start_match = re.match(r"^(`{3,})", stripped)
if start_match:
fence_len = len(start_match.group(1))
stripped = stripped[fence_len:]
# Check for closing fence at end - only strip if fence lengths match
end_match = re.search(r"(`{3,})$", stripped.strip())
if end_match:
end_fence_len = len(end_match.group(1))
# Only strip closing fence if it matches opening fence length (CommonMark spec)
if fence_len == end_fence_len:
This class is important because it defines how gptme Tutorial: Open-Source Terminal Agent for Local Tool-Driven Work implements the patterns covered in this chapter.
scripts/demo_capture.py
The check_tool function in scripts/demo_capture.py handles a key part of this chapter's functionality:
def check_tool(name: str) -> bool:
"""Check if a tool is available."""
return shutil.which(name) is not None
def check_prerequisites(modes: list[str]) -> list[str]:
"""Check required tools and return list of missing ones."""
missing = []
if "terminal" in modes:
if not check_tool("asciinema"):
missing.append("asciinema (pip install asciinema)")
if not check_tool("gptme"):
missing.append("gptme (pip install gptme)")
if "screenshots" in modes or "recording" in modes:
try:
# Check if playwright is importable
subprocess.run(
[
sys.executable,
"-c",
"from playwright.sync_api import sync_playwright",
],
capture_output=True,
check=True,
)
except (subprocess.CalledProcessError, FileNotFoundError):
missing.append(
"playwright (pip install playwright && playwright install chromium)"
This function is important because it defines how gptme Tutorial: Open-Source Terminal Agent for Local Tool-Driven Work implements the patterns covered in this chapter.
scripts/demo_capture.py
The check_prerequisites function in scripts/demo_capture.py handles a key part of this chapter's functionality:
def check_prerequisites(modes: list[str]) -> list[str]:
"""Check required tools and return list of missing ones."""
missing = []
if "terminal" in modes:
if not check_tool("asciinema"):
missing.append("asciinema (pip install asciinema)")
if not check_tool("gptme"):
missing.append("gptme (pip install gptme)")
if "screenshots" in modes or "recording" in modes:
try:
# Check if playwright is importable
subprocess.run(
[
sys.executable,
"-c",
"from playwright.sync_api import sync_playwright",
],
capture_output=True,
check=True,
)
except (subprocess.CalledProcessError, FileNotFoundError):
missing.append(
"playwright (pip install playwright && playwright install chromium)"
)
if not check_tool("gptme-server"):
missing.append("gptme-server (pip install gptme)")
This function is important because it defines how gptme Tutorial: Open-Source Terminal Agent for Local Tool-Driven Work implements the patterns covered in this chapter.
How These Components Connect
flowchart TD
A[Codeblock]
B[workaround]
C[check_tool]
D[check_prerequisites]
E[capture_terminal_demo]
A --> B
B --> C
C --> D
D --> E