Skip to main content

plyngent

Single-user LLM chat and agent toolkit for the terminal.

Python 3.14+. OpenAI-compatible APIs (including DeepSeek OpenAI-compat), OpenAI Responses with optional hosted tools, SQLite session memory, workspace-scoped file/process/VCS tools, and a readline REPL with slash commands.

Requires Python 3.14+ on your PATH (or via uv / pipx).

Install

Quick try (uvx)

No permanent install — runs the published package in a temporary environment:

uvx plyngent --help
uvx plyngent chat

User tool install

Keep plyngent on your PATH as a managed tool:

# uv (recommended)
uv tool install plyngent
plyngent --help

# pipx
pipx install plyngent
plyngent --help

Upgrade later:

uv tool upgrade plyngent
# or: pipx upgrade plyngent

pip (venv or user)

python3.14 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -U pip
pip install plyngent
plyngent --help

Or user install (if you accept that layout):

pip install --user plyngent

From a git clone (development)

pdm install          # first time
pdm sync             # after pull
pdm run plyngent --help

Dev checks (same order as CI):

pdm run ruff check .
pdm run ruff format --check .   # or: pdm run ruff format .  to apply
pdm run basedpyright .
pdm run pytest

Commit gateway (prek): runs ruff check + format and basedpyright on git commit so format is not forgotten.

uv tool install prek    # once
prek install            # once per clone (installs .git/hooks/pre-commit)
prek run --all-files    # run all hooks on demand

Config: prek.toml. CI still runs the same checks in GitHub Actions.

Basic usage

# 1) Create / open config
plyngent config path
plyngent config edit    # $VISUAL/$EDITOR, else system open (xdg-open/open/startfile)

# Minimal provider (OpenAI platform — Responses API; preset defaults to openai):
# [providers.oai]
# access_key_or_token = "sk-..."
# # models default: gpt-5.4, gpt-5.4-mini, gpt-5.4-nano
# # provider_tools default: web_search  (use provider_tools = [] to disable)

# 2) Chat
plyngent chat
plyngent chat --provider oai --model gpt-5.4-mini
plyngent chat -p "Summarize this repo" --provider oai --model gpt-5.4-mini --no-stream

# 3) List providers from config
plyngent providers

# 4) Plugins (entry-point allowlist under [plugins])
plyngent plugins list
plyngent plugins enable acme

In the REPL: type normally, use /help for slash commands, """""" for multiline, /markdown for Rich rendering, /quit to leave.

Configure

Default config path (platformdirs):

plyngent config path
plyngent config edit    # $VISUAL/$EDITOR (e.g. codium --wait), else system default

Copy the example and fill in a real token:

cp doc/plyngent.example.toml "$(plyngent config path)"
# then edit providers

Minimal shape:

[providers.local]
preset = "openai-compatible"
url = "https://api.openai.com/v1"
access_key_or_token = "sk-..."
# Optional HTTP timeouts (seconds). Default: connect=10, read=600.
# timeout = 120
# timeout = { connect = 10, read = 600 }

[providers.local.models]
"gpt-4o-mini" = { text = true }

[agent]
# system_prompt = persona (omit → built-in). tool_directives = tool playbook.
# system_prompt = "" / tool_directives = "" disable each part; both "" → no system.
# Or multi-line override (prefer '''...'''):
# system_prompt = '''Your custom persona...'''
# tool_directives = '''### Workspace ...'''
confirm_destructive = true
max_context_tokens = 200000
# Fold MCP server initialize ``instructions`` (usage guidance) into the
# system prompt when tools are on (default true; false ignores server text).
# mcp_instructions = true
# Static out-of-workspace pre-allow (path → read|write|exec); never prompts.
# allow_paths = { "/data/datasets" = "read", "/tmp/build" = "exec" }
# Auto-raise tool/PTY limits without prompting (same as answering yyy).
# auto_continue_limits = false

# Optional plugins (entry-point names); default load none. See doc/plugins.md.
# [plugins]
# enable = ["acme"]

Per-provider timeout is passed to the HTTP session for chat/completions, Responses, and GET /models. A single number sets one timeout; { connect, read } splits TCP/TLS setup vs idle wait between response bytes (SSE can run longer than read while chunks keep arriving). Tool/process timeouts (run_argv, PTY, policy confirm) are separate.

Third-party plugins: install a package that declares project.entry-points."plyngent.tools" (and later other groups), then allowlist the entry-point name under [plugins].enable. Details: doc/plugins.md.

MCP servers (Model Context Protocol over stdio): define servers under [mcp.servers.<name>] (command + args, optional env/cwd/timeout/read_only) and their tools become agent tools namespaced mcp__<server>__<tool> (LOCAL tags; read_only = true also marks them READ_ONLY, eligible for /btw --tools=read). Names in [mcp].disable stay disconnected. A server may also return optional instructions (usage guidance) in its MCP initialize response; when tools are on those are folded into the agent system prompt as MCP server <name> instructions: blocks ([agent] mcp_instructions = false disables), and /mcp previews them. In the REPL, /mcp lists per-server status and tool counts; /mcp reconnect re-reads the config file and restarts every enabled server (adopts newly added ones).

Supported provider presets today:

Preset API used by the agent Notes
openai (default if preset omitted) OpenAI Responses (POST /responses) Default models gpt-5.4 / gpt-5.4-mini / gpt-5.4-nano when models is omitted; optional provider_tools (default web_search)
openai-compatible Chat Completions Generic hosts (vLLM, LiteLLM, proxies); requires url
deepseek Chat Completions (DeepSeek) Default models deepseek-v4-flash / deepseek-v4-pro when models is omitted; set convention = "responses" (provider or per-model) to use the OpenAI Responses API (POST /responses, currently only deepseek-v4-flash), or convention = "anthropic" to use the Anthropic Messages API on https://api.deepseek.com/anthropic
anthropic Anthropic Messages (POST /messages) Native tools/streaming; set access_key_or_token (API key)

Model-level preset / url overrides on a catalog entry can route a single provider name to a different API (e.g. gateway + Anthropic model). DeepSeek models may also carry a per-model convention (empty = inherit the provider-level one), e.g. serve deepseek-v4-flash over Responses while deepseek-v4-pro stays Chat Completions:

[providers.deepseek]
preset = "deepseek"
access_key_or_token = "sk-..."

[providers.deepseek.models]
"deepseek-v4-flash" = { text = true, convention = "responses" }
"deepseek-v4-pro" = { text = true }

DeepSeek's Anthropic convention (convention = "anthropic") points at https://api.deepseek.com/anthropic by default and is fully supported by the agent's Anthropic Messages path (tools, streaming, usage). DeepSeek maps claude-opus* model ids to deepseek-v4-pro and claude-haiku* / claude-sonnet* (and unknown ids) to deepseek-v4-flash server-side; real deepseek-v4-* ids pass through as-is. GET /models is not documented on that base, so model selection is config-driven.

If [database] is omitted (or SQLite url is unset/empty), chat uses a durable file under the user data dir (e.g. ~/.local/share/plyngent/chat.db on Linux). Set url = ":memory:" for a true in-memory SQLite (CLI warns; no file; useful for tests).

Chat

Interactive REPL

plyngent chat
plyngent chat --provider local --model gpt-4o-mini
plyngent chat --workspace /path/to/project --new
plyngent chat --session 3
Flag Meaning
--provider / --model Select from config (required when multiple and non-interactive)
--workspace Tool root (default: cwd); sessions bind to this path
--new / --session ID Fresh session vs resume by id
--tools / --no-tools Default tools on
--max-rounds Tool-loop rounds per turn (default 32)
--stream / --no-stream Streaming deltas (default on)
--quiet Less status on stderr
--yes YOLO on: skip destructive-tool confirms for this process
--auto-continue Auto-raise tool/PTY limits without prompting (like answering yyy)
--log-level On the root CLI: DEBUG, INFO, WARNING, …

Sessions resume the most recently updated session for the current workspace unless you pass --new or --session. Each session remembers the last provider and model (restored on resume so you are not re-prompted).

When a tool-loop or PTY limit is hit, the prompt accepts y (continue once), n (stop), or yyystop asking for the rest of this turn (the next user turn prompts again). --auto-continue / [agent] auto_continue_limits = true skip the prompt for every turn.

One-shot (scripts / CI)

plyngent chat -p "Summarize README.md" --provider local --model gpt-4o-mini --no-stream
echo "hello" | plyngent chat --provider local --model gpt-4o-mini

Exit codes (one-shot):

Code Meaning
0 Success
1 Config / usage error
2 Cancelled
3 Turn failed (API / incomplete)

Input ergonomics

  • Multiline: start a message with """, end a later line with """.
  • /edit: compose a turn in $VISUAL/$EDITOR (blocking only; empty cancels).
  • Tab: completes slash commands and some arguments (provider, model, on/off, export, /help targets).

Slash commands

Type /help in the REPL for the live list. Common ones:

Command Purpose
/status Provider, session, context/usage estimates
/history [n|last] Recent messages (default preview; last/1 = full + markdown)
/history --full Full bodies for the selected window
/sessions Sessions for this workspace
/new /resume /rename /delete Session lifecycle (/delete confirms)
/export [md|json] [path] Transcript from DB (no secrets)
/compact Soft-compact + model summary into a new session
/stream /verbose /markdown /tools /rounds Toggles and limits
/yolo [on|off|once] Soft destructive confirms: sticky skip, off, or next turn only

| /retry | Re-run incomplete last user turn (after error/cancel) | | /btw [--tools read\|no\|full] [--fresh] | Side question without changing the main session (read-only tools by default) | | /provider /model | Switch without restarting | | /model --persist | Save current model id into plyngent.toml catalog | | /models | List config + remote GET /models (always re-fetches) | | /models --persist | Merge remote catalog into TOML for this provider | | /todos | Todo/task stack: list, push, pop, done, clear | | /grants | Directory-access grants: list, or revoke <index\|all> | | /config | Edit plyngent.toml ($VISUAL/$EDITOR or system open); reload after blocking editor | | /quit | Leave the REPL |

User messages are saved immediately. On API error or Ctrl+C, partial assistant/tool output is discarded but the user message stays so /retry works after resume. Interactive auto-retry uses 10s / 20s / 30s delays.

Workspace model

  • Workspace = root for file/process/VCS tools (default cwd).
  • Session = SQLite chat bound to a workspace path.
  • Paths outside the workspace need a directory-access grant: the model calls request_directory_access (read / write / exec), the human approves at the requested level or another one (timed y/N, default deny; --yes//yolo auto-approve as a process-only grant), and approval lasts for the session (/grants lists/revokes). Static pre-allow lives under [agent].allow_paths. The path denylist always wins, and grants gate path-resolving tools only — they are not a sandbox (run_argv/PTY reach the whole filesystem).
  • Resuming a session from another directory prompts: keep session workspace, rebind to current, or abort.

Tools (when enabled)

Default registry: file ops (including tree with a markdown bullet-list default, flat paths or classic decorated on demand; default noise-dir skips), run_argv / run_argv_batch / PTY (POSIX openpty; Windows ConPTY via pywinpty), read-only VCS (git), HTTP fetch (GET/POST/PUT/DELETE via niquests; private/loopback hosts need a human policy grant, not YOLO), human prompts (ask_user_line / ask_user_choice / ask_user_form), wait (line prompt with timeout; Enter disturbs), request_directory_access (out-of-workspace access grants), get_truncated (resume any truncated result via its truncate_token=...), and todo stack tools (todo_list / todo_push / todo_pop / todo_update / todo_clear).

Safety defaults:

  • Paths stay under the workspace unless granted (request_directory_access / [agent].allow_paths); optional path_denylist substrings always apply (tree also skips denylisted children by default).
  • Command basename denylist (e.g. dangerous shells/utilities).
  • Destructive tools (delete/move/overwrite) can require confirm (confirm_destructive; default deny in non-TTY). Override for the session with /yolo on|off|once or startup --yes (path/command denylists still apply).
  • PTY sessions: caps, idle TTL, output budget; master FD is non-inheritable; sessions closed on chat exit. Prefer file tools over full-screen editors (vim/nano) for edits. read_pty sanitizes CSI/controls so tool results cannot reprogram the host TTY (no host terminal reset on exit). write_pty is literal text only; use write_pty_keys for \xHH, ctrl+x, key=esc|enter|…. For passwords/sudo/ssh prompts use ask_into_pty (human types locally; answer never returns to the model).

Usage / context (CLI)

  • Context size prefers API prompt_tokens from the last model call; otherwise a char-based estimate (~4 chars/token).
  • Turn/session usage sum billed completion usage across tool rounds (history is re-sent each round).
  • Soft compact can calibrate from reported prompt_tokens. See /status.

Other commands

plyngent providers          # list configured providers
plyngent config path|edit
plyngent --log-level INFO chat ...

Architecture (short)

See doc/architecture.md and AGENTS.md for developers.

  • lmproto/ — OpenAI-compatible, OpenAI Responses, Anthropic Messages, DeepSeek msgspec models and async SSE clients
  • agent/ — kind-based tool loop (chat_completions / responses / messages), streaming, usage, compact
  • memory/ — async SQLAlchemy sessions/messages
  • tools/ — workspace tools
  • cli/ — Click entry + slash registry (awaitlet bridges sync Click to async work)
  • Multi-tenant / web (router/, real web/) are not in scope for the single-user CLI (Phase H).

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plyngent-0.6.0.tar.gz (306.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plyngent-0.6.0-py3-none-any.whl (263.6 kB view details)

Uploaded Python 3

File details

Details for the file plyngent-0.6.0.tar.gz.

File metadata

  • Download URL: plyngent-0.6.0.tar.gz
  • Upload date:
  • Size: 306.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for plyngent-0.6.0.tar.gz
Algorithm Hash digest
SHA256 060fd270403f1795cea127119047199b4ae89d0b7169da7ae72811096c51d028
MD5 6e1a33869228ec1e87560b343bf8dc82
BLAKE2b-256 2395c2464f56f2a0e28bcf3e502eb7808e05792abf29148c8c3405d5ae22b580

See more details on using hashes here.

Provenance

The following attestation bundles were made for plyngent-0.6.0.tar.gz:

Publisher: ci.yml on NCBM/plyngent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file plyngent-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: plyngent-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 263.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for plyngent-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 db377f44a3045ffceadcfb067e929e30bc5bdd6e96866554ae6f7bfa4b0ab9d8
MD5 05320979dd0499a74d64624f5321588b
BLAKE2b-256 41af6ad39b70a67e94b084b1db549bf8b6f6695bcd09e50bbe9bfdbecce60443

See more details on using hashes here.

Provenance

The following attestation bundles were made for plyngent-0.6.0-py3-none-any.whl:

Publisher: ci.yml on NCBM/plyngent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page