Skip to main content

Mindweft

Mindweft (formerly Minigent) is a minimal FastAPI agent runtime proof of concept based on DESIGN.md. It provides a small HTTP API for thread-based chat, local and MCP-backed tools, pluggable LLM adapters, and optional CLI, browser, voice, peer-agent, and quality-review workflows.

Highlights

  • FastAPI service with thread/message APIs and streaming run events.
  • In-memory thread store by default, with optional SQLite persistence.
  • Simple agent execution loop with a pluggable local tool registry.
  • Replaceable LLM adapter boundary for mock, OpenAI, OpenRouter, OpenAI-compatible, and generic OAuth-backed providers.
  • Optional MCP tool discovery and invocation over HTTP.
  • Optional local/peer-agent backend and peer-agent tool delegation.
  • Optional browser, CLI, and voice clients.
  • Optional privacy-preserving remote quality critique of sanitized local drafts.

Quickstart

uv venv
source .venv/bin/activate
uv sync --dev
uv run uvicorn app.main:app --reload

Open the production console foundation:

http://127.0.0.1:8000/console/

Assistant responses in the production console render safe GitHub Flavored Markdown, including headings, lists, tables, task lists, links, blockquotes, and fenced code. Raw HTML is disabled; user and tool-authored content remains plain text by default. The console typography baseline is 15px for body text, 16px for chat, 14px for controls, 13px for labels and code, and 12px for tertiary metadata; mobile form controls remain 16px to avoid browser input zoom.

The dependency-free development client remains available during migration:

http://127.0.0.1:8000/web/

Or use the packaged CLI from the repo:

uv run mindweft run "hello"
uv run mindweft chat

The legacy minigent and minigent-client commands remain available as compatibility aliases. Canonical Python imports are also available from mindweft_client, mindweft_config, mindweft_mcp, and mindweft_workspace now own the implementations. The corresponding minigent_* import packages remain available as compatibility aliases and resolve public modules to the same implementation objects. The installable distribution is named mindweft; legacy minigent_* import packages and minigent-* console aliases remain included for source and command compatibility. See Migrating from Minigent for upgrade guidance and the change history for release-level changes.

For the reusable coding-workspace runner, copy .env.coding.template to .env.coding. When storage paths are not configured, the runner uses durable thread and attachment databases under $XDG_STATE_HOME/mindweft, falling back to ~/.local/state/mindweft. During the rename, an existing minigent state directory remains in use until it is moved explicitly, so the runner does not create empty replacement databases or move live SQLite files automatically. MINDWEFT_CODING_WORKSPACES can be one path or a comma-separated list of workspace roots (MINDWEFT_CODING_WORKSPACE is still accepted for compatibility). Pass --no-env-file to mindweft-coding-workspace to skip reading .env.coding and use only the process environment plus unified config. Mindweft discovers a cwd-local ./mindweft.toml first, then the legacy ./minigent.toml, followed by $XDG_CONFIG_HOME/mindweft/mindweft.toml and the legacy Minigent user path. See Coding workspace setup for the MCP-based workspace tool model, bridge path glob controls, optional trusted-local shell command support, and optional codebase-memory/code-navigation MCP setup.

For a user-operated agent, see User MCP for the principal-scoped MCP v2 endpoint at /user-mcp, which reports personal execution configuration and effective MCP access without exposing credentials and supports scoped user-owned configuration updates. For an administrator-operated agent, see Admin operations MCP for the read-only in-process MCP v2 endpoint at /mcp, its authentication model, safe setup diagnostics, the same role-scoped operations available directly to authenticated admin chat, and the platform-admin execution editor used to bootstrap that chat without tenant configuration.

Mindweft configuration names are available during the rename: MINDWEFT_* values take precedence over matching MINIGENT_* values, mindweft.toml is discovered before minigent.toml, and $XDG_CONFIG_HOME/mindweft/mindweft.toml is checked before the legacy user-level path. Legacy names remain supported for deployment and local-state compatibility.

Basic API flow

curl -X GET 'http://127.0.0.1:8000/threads?limit=20' \
  -H 'Authorization: Bearer dev-token'

curl -X POST http://127.0.0.1:8000/threads \
  -H 'Authorization: Bearer dev-token'

curl -X POST http://127.0.0.1:8000/threads/<thread_id>/messages \
  -H 'Authorization: Bearer dev-token' \
  -H 'content-type: application/json' \
  -d '{"content":"hello"}'

curl -X POST http://127.0.0.1:8000/threads/<thread_id>/run \
  -H 'Authorization: Bearer dev-token'

curl -X PATCH http://127.0.0.1:8000/threads/<thread_id>/title \
  -H 'Authorization: Bearer dev-token' \
  -H 'content-type: application/json' \
  -d '{"title":"Investigate token refresh failures"}'

Thread titles are stored canonically by the service. The first message supplies an immediate fallback title. After each successful run, Mindweft asynchronously asks the thread's selected LLM for a concise semantic title using a bounded excerpt of user and assistant messages; tool payloads are excluded, INSUFFICIENT_CONTEXT leaves the fallback in place, and a successful semantic title is generated only once. PATCH /threads/<thread_id>/title sets a manual title that automatic generation never replaces. Thread lists also return the selected skill, capability profile, and LLM profile so clients can show those separately from the title.

Backfill existing fallback titles explicitly so ordinary thread reads remain free of hidden LLM calls. Preview eligibility first, then run with bounded concurrency:

mindweft threads retitle --dry-run --limit 50
mindweft threads retitle --limit 50 --concurrency 2

The operation is resumable: manual and semantic titles are skipped, as are empty threads.

For live progress, use POST /threads/<thread_id>/run/stream. It returns newline-delimited JSON events for run start/completion, LLM requests/responses, tool calls/results, peer-agent progress, and final assistant messages.

Configuration at a glance

For desktop/local use, start from mindweft.toml.template or write a focused starter config with uv run mindweft config init --profile local-coding (basic-chat, openrouter, and voice profiles are also available). This file is a friendly facade for the common app, auth, LLM, coding workspace, MCP, voice, and quality settings. Unified TOML discovery first checks ./mindweft.toml, then legacy ./minigent.toml, then the Mindweft and Minigent user-level paths. The coding-workspace runner separately defaults its dotenv file to ./.env.coding unless --no-env-file is set. See docs/mindweft-toml.md for the schema, examples, precedence, and troubleshooting commands. Set MINDWEFT_CONFIG_FILE (or legacy MINIGENT_CONFIG_FILE) to point at a different TOML file. Existing .env files and real environment variables still work; set MINDWEFT_DOTENV_FILE (or legacy MINIGENT_DOTENV_FILE) to load a dotenv file other than .env. A single TOML file can hold multiple named LLM profiles under [llm.providers.<name>]; choose the default with llm.default and bind a new thread with mindweft chat --llm <name>, mindweft run --llm <name>, or the browser settings. Tests or subprocesses that need to ignore cwd-local default files can set MINDWEFT_CONFIG_DISCOVERY=disabled (or the legacy Minigent name) while still honoring explicit config paths. Precedence is environment > selected .env > mindweft.toml > defaults, so deployment and secret-management workflows can keep using env overrides. Use uv run mindweft config print --resolved to inspect the local resolved env mapping with secret-looking values masked, or uv run mindweft config export to generate a best-effort TOML facade from a running server. uv run mindweft config doctor also checks the unified config file, LLM provider prerequisites, coding workspace paths, shell allowlists, and MCP server shape before probing a running API.

Start from .env.template for full local or deployment settings. Common knobs:

Setting Purpose
MINDWEFT_AUTH_MODE Authentication mode: development headers, static tokens, or JWT.
MINDWEFT_SESSION_CREDENTIALS / MINDWEFT_SESSION_SECRET Optional generic username/password-hash console sign-in with secure same-origin sessions.
MINDWEFT_ADMIN_DB_PATH / MINDWEFT_ADMIN_ENCRYPTION_KEY Durable encrypted tenant administration, execution configuration, and write-only user MCP credential headers. The encryption key is required before personal credentials can be stored or used.
MINDWEFT_ADMIN_MCP_SERVER_CATALOG / MINDWEFT_ADMIN_MCP_SERVER_CATALOG_SECRET Deployment-owned MCP definitions that platform admins can assign as a tenant ceiling and narrow per role or user; use the _SECRET variant when entries contain credentials.
MINDWEFT_ADMIN_EXTERNAL_GRANT_PROVIDERS Optional provider-neutral administrative HTTP grant integrations; disabled when unset and excluded from runtime readiness and model tooling. Suspended/deleted users are durably queued for assignment cleanup and grant disabling.
MINDWEFT_USER_DEPROVISIONING_INTERVAL_SECONDS / MINDWEFT_USER_DEPROVISIONING_MAX_ATTEMPTS Poll interval and retry limit for durable user lifecycle deprovisioning (defaults: 5 seconds and 8 attempts).
MINDWEFT_LLM_PROVIDER LLM provider such as mock, openai, openrouter, openai-compatible, generic-oauth, google, or anthropic.
MINDWEFT_LLM_MODEL Model identifier for the selected provider.
MINDWEFT_IMAGE_INPUT_ENABLED Enables image attachments from CLI/chat clients; unified config key is [image_input].enabled.
MINDWEFT_ATTACHMENT_DB_PATH Optional SQLite store for uploaded attachment bytes; unified config key is [attachments].db_path.
MINDWEFT_ATTACHMENT_ENCRYPTION_KEY / MINDWEFT_ATTACHMENT_ENCRYPTION_KEYS Optional AES-256-GCM key or versioned keyring for attachment bytes at rest.
MINDWEFT_RATE_LIMIT_DB_PATH Optional shared SQLite token-bucket state for upload and run rate limits.
MINDWEFT_THREAD_DB_PATH Optional SQLite path for persistent thread/message storage plus atomic cross-replica run leases and cancellation.
MINDWEFT_OAUTH_STORE_PATH / MINDWEFT_OAUTH_ENCRYPTION_KEYS Shared encrypted SQLite OAuth credentials, login-flow state, and coordinated multi-replica token refresh.
MINDWEFT_TENANT_EXECUTION_CONFIGS Optional per-tenant LLM, tool, skill, capability, backend, and quality config. Tenant execution config supplies shared resources; the partially implemented user execution overlay adds personal agents, live personal skills, narrowing-only capability profiles, and policy-gated public HTTPS personal MCP servers without tenant config edits. Encrypted static credential headers are supported; interactive OAuth connection and refresh flows remain pending.
MINDWEFT_MCP_BROKER_ENABLED Enables the peer-agent MCP broker path when using peer backends.
MINDWEFT_MCP_BROKER_DB_PATH Optional shared SQLite path for cross-replica MCP broker sessions; bearer tokens are stored only as SHA-256 hashes.
MINDWEFT_TOOL_TIMEOUT_SECONDS Default wall-clock limit for each runtime tool call before returning a structured timeout error.
MINDWEFT_RESPONSES_REASONING_ONLY_RETRIES Bounded generic OAuth Responses continuations after reasoning-only output before reporting a retryable provider stall.

See the full reference for the complete environment and tenant config surface.

Built-in local tools

The local tool registry includes:

  • echo
  • current_time
  • fetch_url
  • sleep
  • calculator
  • retrieve_knowledge, when MiniRAG is configured and allowed
  • peer_agent_task, when MINDWEFT_ENABLE_PEER_AGENT_TOOL=true and allowed

Tool availability can be narrowed per tenant, skill, and capability profile. Workspace capabilities such as filesystem access, editing, shell commands, test runs, builds, and git operations should be exposed through MCP servers and capability profiles, not as default Mindweft local tools.

Tool results are redacted at the registry boundary before they are streamed to clients, stored in thread history, or supplied to later LLM turns. The built-in redactor removes values under sensitive-looking keys and secrets in URL query parameters on a best-effort basis; it is not a substitute for avoiding unnecessary access to credentials. Tenant and MCP server configs can override the tool-result redaction policy with result_redaction / resultRedaction (mode: best_effort, full, or none).

As an experimental local privacy convention, an MCP tool can return model-safe {{pii:kind:reference}} placeholders in structuredContent and place the corresponding string values under _meta["io.minigent/private-values"]. Mindweft removes that metadata before model context, thread history, and run events, and resolves placeholders in replies sent to the authenticated user. This is a proof of concept rather than a standard MCP confidential channel: other MCP clients may log or expose _meta. Stored messages retain placeholders, while authenticated message reads rehydrate values that have not expired. Private values expire after 30 minutes by default and are bounded to 1,000 references per user/thread scope and 10,000 characters per value; override those limits with MINDWEFT_PRIVATE_VALUE_TTL_SECONDS, MINDWEFT_PRIVATE_VALUE_MAX_REFS_PER_THREAD, and MINDWEFT_PRIVATE_VALUE_MAX_CHARS.

The legacy _meta["io.minigent/carddav-private-values"] key remains accepted during the DAV sidecar migration, but new MCP servers should emit the protocol-neutral key. Tools that inspect raw user text before model use must be explicitly trusted and hidden with the MCP server's trusted_input_preprocessor_tools list; Mindweft does not trust server-provided descriptions for this boundary.

Private values remain in memory by default. To make private values, consent grants, audit records, and resumable pending tool actions restart-safe, configure encrypted SQLite storage. The consent tables may share the private-value database file and key; they remain separate from the thread database:

PRIVATE_DATA_KEY="$(python -c 'import base64,secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())')"
export MINDWEFT_PRIVATE_VALUE_DB_PATH="$PWD/.data/private-data.db"
export MINDWEFT_PRIVATE_VALUE_ENCRYPTION_KEY="$PRIVATE_DATA_KEY"
export MINDWEFT_PRIVATE_CONSENT_DB_PATH="$PWD/.data/private-data.db"
export MINDWEFT_PRIVATE_CONSENT_ENCRYPTION_KEY="$PRIVATE_DATA_KEY"
# Active key versions; see the rotation workflow below before changing them:
export MINDWEFT_PRIVATE_VALUE_KEY_VERSION=1
export MINDWEFT_PRIVATE_CONSENT_KEY_VERSION=1

The SQLite stores encrypt each private value and each consent/action payload independently with AES-256-GCM and a fresh 96-bit nonce. Private-value tenant/user/thread/reference metadata and the declared PII kind, plus consent/action tenant/user/thread/consent metadata, are authenticated as associated data. A known reference resolves only when its placeholder retains that declared kind; relabeled placeholders remain unresolved for display and fail closed for tool disclosure. Private values are resolvable only by the user who created or received them, even when another user in the same tenant can access the thread's placeholder-bearing messages. The database contains ciphertext, nonces, scoped metadata, statuses, and expiry timestamps but not keys or plaintext values/tool arguments. Keys must come from the process environment or an external secret manager; do not commit them or place them beside the database. Startup fails closed when a database path is configured without a valid corresponding key. Back up keys separately: losing all copies of a required version makes its existing records unrecoverable. Consent requests default to a ten-minute TTL and grants to five minutes; override them with MINDWEFT_PRIVATE_CONSENT_REQUEST_TTL_SECONDS and MINDWEFT_PRIVATE_CONSENT_GRANT_TTL_SECONDS. Redacted disclosure audit records are retained for 30 days by default and bounded to the newest 1,000 records per tenant/user/thread scope in both memory and SQLite. Configure those bounds with MINDWEFT_PRIVATE_CONSENT_AUDIT_TTL_SECONDS and MINDWEFT_PRIVATE_CONSENT_MAX_AUDIT_RECORDS_PER_SCOPE. Expired and over-limit records are pruned during consent activity, audit reads, and encrypted-store startup.

Upgrading a private-value database created before user scoping intentionally drops its short-lived private_values rows on first startup. Those legacy rows cannot be attributed to a specific user safely; thread messages retain unresolved placeholders until new values are captured. Consent requests, action records, disclosure audits, and thread history are not removed.

For key rotation, both encrypted stores accept a JSON keyring whose keys are positive version numbers and whose values are base64-encoded 32-byte keys. New writes use the version selected by *_KEY_VERSION; older versions are decryption-only. To rotate a shared private-data key from version 1 to version 2:

OLD_PRIVATE_DATA_KEY='...version-1 key from the secret manager...'
NEW_PRIVATE_DATA_KEY="$(python -c 'import base64,secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())')"
PRIVATE_DATA_KEYS="{\"1\":\"$OLD_PRIVATE_DATA_KEY\",\"2\":\"$NEW_PRIVATE_DATA_KEY\"}"

unset MINDWEFT_PRIVATE_VALUE_ENCRYPTION_KEY MINDWEFT_PRIVATE_CONSENT_ENCRYPTION_KEY
export MINDWEFT_PRIVATE_VALUE_ENCRYPTION_KEYS="$PRIVATE_DATA_KEYS"
export MINDWEFT_PRIVATE_CONSENT_ENCRYPTION_KEYS="$PRIVATE_DATA_KEYS"
export MINDWEFT_PRIVATE_VALUE_KEY_VERSION=2
export MINDWEFT_PRIVATE_CONSENT_KEY_VERSION=2
export MINDWEFT_PRIVATE_VALUE_REENCRYPT_ON_STARTUP=true
export MINDWEFT_PRIVATE_CONSENT_REENCRYPT_ON_STARTUP=true

Start Mindweft once with both keys available. On startup, each store transactionally re-encrypts its surviving rows: private values in one transaction, then consent requests, pending actions, and disclosure audit records in another. Then stop it, remove version 1 from both keyrings, disable both *_REENCRYPT_ON_STARTUP flags, and restart. A successful restart with only version 2 verifies that no stored row still requires the retired key. Keep a protected backup until that verification succeeds. Rotation fails closed and rolls back if any required old key is missing or any ciphertext fails authentication. The legacy singular *_ENCRYPTION_KEY settings remain supported and represent the active *_KEY_VERSION; they can also be combined with a keyring when their key agrees with its active version.

User-authored message text is locally preprocessed before storage or model use. The default conservative detector masks email addresses, phone-number-like values, street addresses, and person names in explicit contexts such as Email Jane Doe, Dr. Jane Doe, or Jane Doe's. Existing private placeholders are preserved. This regex-based detector is not a complete PII classifier: it can miss unfamiliar formats, single names without a contextual cue, non-US-style addresses, and other identifiers, and it can produce false positives. Set MINDWEFT_INPUT_PII_PROTECTION_ENABLED=false to disable it explicitly.

Private placeholders are denied at every tool boundary by default. An explicitly trusted MCP tool can receive selected values only when its server configuration opts into resolve_selected and allowlists the exact JSON argument paths. Resolution happens after the model creates the tool call and after placeholder-only argument logging, immediately before the trusted handler runs; the handler receives resolved arguments but never receives the private-value resolver capability itself. Unapproved paths fail with HTTP 403, and missing or expired values fail closed. Array paths use [*], for example:

{
  "name": "trusted-mail",
  "url": "http://127.0.0.1:9000/mcp",
  "allowed_tools": ["send"],
  "private_value_policy": "deny",
  "private_value_tool_policies": {
    "send": {
      "mode": "resolve_selected",
      "argument_paths": ["recipient.email", "cc[*].email"],
      "requires_approval": true
    }
  }
}

pass_through is also available for tools designed to consume opaque placeholders directly; it never resolves their values. Set requires_approval on a per-tool policy to require the same one-shot approval flow even when a call has no private placeholders, such as a destructive delete. Tool results are run back through local PII protection before storage, run events, or another model turn.

A selected disclosure now requires a user-scoped consent grant in addition to administrator policy. Before requesting consent, Mindweft validates every selected placeholder against its user/thread scope, expiry, reference, and declared PII kind without exposing the plaintext to the tool layer. Missing, expired, or relabeled placeholders fail with HTTP 409 and create no consent request, pending action, or disclosure audit record. The first valid attempt creates a redacted pending request, emits a private_value.consent_required run event, and fails the tool call with HTTP 428. The request contains only the tool name, an argument fingerprint, and PII kinds, counts, and argument paths. Clients can inspect and decide it through:

GET  /threads/{thread_id}/private-value-consents/pending
POST /threads/{thread_id}/private-value-consents/{consent_id}
POST   /threads/{thread_id}/private-value-consents/{consent_id}/resume
GET    /threads/{thread_id}/private-value-actions
DELETE /threads/{thread_id}/private-value-actions/{consent_id}
GET    /threads/{thread_id}/private-value-disclosures/audit

The decision body is {"approve": true, "one_shot": true} or {"approve": false}. The resume endpoint validates that the private values are still available before atomically claiming and executing the exact placeholder-bearing tool call that originally requested consent, then continues the agent loop from its protected result; the model does not need to reconstruct the call. An expired value therefore leaves the action pending rather than incorrectly marking its external outcome as uncertain. Claiming is atomic and durable: concurrent or post-restart attempts to claim the same action fail with HTTP 409 instead of invoking a potentially side-effecting tool twice. If the process crashes, times out, or loses its connection after the claim, the action remains in an executing state and is not automatically replayed because the external outcome may be unknown. The claimed record is retained only until its consent grant expires (five minutes from the decision by default), then removed during consent activity or encrypted-store startup. GET /private-value-actions returns only consent ID, tool name, state, and expiry—never tool arguments or private values. After reconciling an uncertain external outcome, clients can DELETE the action record; discarding also revokes an unconsumed approval and appends a redacted discarded audit event. Interactive mindweft chat sessions expose the /actions and /discard-action <consent-id>. Reconcile the tool's external state before creating a replacement action; tools should still support idempotency keys where possible. Grants are fingerprint of the complete placeholder-bearing argument object, so changing the body or any other argument requires new consent. Non-one-shot grants remain usable for five minutes; pending requests expire after ten minutes. Denials block the identical disclosure until they expire. Consent state is scoped by tenant, user, and thread. Audit records contain opaque references, paths, and kinds, but never raw values. The browser displays a confirmation dialog and automatically resumes an approved action. If that resume has an uncertain outcome, it detects the durable executing state, blocks automatic replay, warns the user to check the external system, and offers to discard the reconciled action record. Interactive mindweft chat sessions show the same redacted consent summary and prompt for a one-shot approval. Consent grants, audit records, and exact placeholder-bearing pending actions survive restarts when encrypted consent storage is configured; otherwise they remain in memory.

Private CardDAV and CalDAV server implementations live in the separate private-dav-mcp project. Mindweft retains only the generic private-value envelope, trusted-preprocessor, selective-disclosure, approval, audit, and rehydration machinery. Configure DAV servers as ordinary MCP endpoints and explicitly list any runtime-only input tool under trusted_input_preprocessor_tools; keep mutation approval and selected argument paths in private_value_tool_policies. DAV credentials and protocol-specific environment variables belong on the external sidecar, not the Mindweft process.

Clients

Browser

The API serves the new TypeScript/React console at /console/. The initial production UI foundation includes a responsive, accessible application shell with persistent light/dark theme selection, live readiness checks, a conversation workspace with thread history, message composition, NDJSON run streaming, activity inspection, cancellation controls, context usage inspection, raw model-context previews, and confirmed compaction. On narrow screens, the conversation rail is collapsed by default and available from the Conversations menu so the active chat retains the screen space. The console also supports validated image selection, authenticated binary uploads, attachment previews, and per-image detail controls, one-time private-value approval/denial, pending-consent recovery after reload, uncertain-action reconciliation, a personal setup workspace for versioned execution-overlay JSON plus write-only encrypted MCP credential creation, rotation, and deletion, a tenant-owner settings workspace for profile, membership, password onboarding, domains, read-only entitlements, execution configuration, and tenant-scoped OpenAI OAuth credential import from Pi, and a separate platform administration workspace with tenant provisioning and editing, user role/status management, domain verification, typed feature and limit entitlement editing with server validation, version visibility and confirmed reset, a sectioned execution configuration editor for LLMs, tools, MCP servers (including deployment-configured quick-add cards for hosted internal services), backends, quality review, skills, capability profiles, and agent presets with redacted-secret preservation and unsaved-change protection, tenant-scoped thread browsing with runtime filters, retained-message and compacted-context inspection, previewed pruning, confirmed deletion, and paginated audit review, conflict feedback, confirmed removals, tenant search, attachment and run-capacity metrics, confirmed lifecycle transitions, typed API transport, TanStack Query request lifecycle management, and connection modes for same-origin sessions, in-memory bearer tokens, and trusted-local development headers. Session mode is the production default but requires a session endpoint backed by the deployment's identity provider; the current API authentication modes continue to use bearer tokens or development headers. The console never persists bearer tokens or development principal values in browser storage.

For frontend development, run the API and Vite development server in separate terminals:

uv run uvicorn app.main:app --reload
cd web
npm ci
npm run dev

Vite proxies API calls to http://127.0.0.1:8000. Validate the frontend locally with:

cd web
npm run lint
npm test
npm run build

The local build writes generated files to web/dist, which is ignored by Git. Production assets are rebuilt automatically in the production Docker image and copied into the API's /console/ static directory; generated files under app/static/console are not committed.

Install Chromium once and run the browser suite against the production Vite build:

npm run test:e2e:install
npm run test:e2e

Playwright covers desktop and mobile Chromium, authentication header behavior, browser-storage safety, responsive navigation, and automated axe accessibility checks. Use npm run test:e2e:ui for interactive debugging. CI environments should install Chromium and its system dependencies with npx playwright install --with-deps chromium.

The existing dependency-free browser client remains at /web/ as a lightweight development fallback. It uses the streaming run endpoint to show live LLM, tool, and peer-agent progress, with mobile-friendly run controls, a stop action, basic assistant markdown rendering, execution option selectors, image file selection, mobile camera capture, drag-and-drop, and clipboard paste with previews and per-image detail controls when server image input is enabled; the browser streams binary image bodies to thread-scoped attachment storage instead of base64-wrapping them, then keeps references in message history. Browser responses include MIME-sniffing, framing, referrer, permissions, and Content Security Policy headers; the CSP limits scripts and network requests to the Mindweft origin while allowing same-origin, blob, and data image previews. A mobile More menu provides secondary actions, alongside a thread context sheet with compaction controls, a thread drawer backed by GET /threads, thread refresh/delete actions, and a collapsible activity sheet for run details.

Mobile UI demo

The /web/ client is designed to work in a narrow mobile viewport. To demo it on macOS without a phone, use a browser device emulator:

  • Chrome/Brave: open DevTools with Option+Command+I, then toggle device mode with Command+Shift+M.
  • Safari: enable developer features, then use Develop → Enter Responsive Design Mode or Option+Command+R.

Use a viewport around 390 × 844 to approximate a modern phone. Send a prompt, then tap the Activity bar to open the mobile bottom sheet with run events. During a running request, Send changes to Stop.

To demo on an actual mobile device, bind the development server to your LAN interface. For the plain API server, pass uvicorn's --host option:

uv run uvicorn app.main:app --host 0.0.0.0 --port 8000
ipconfig getifaddr en0

If you start Mindweft through the coding-workspace runner, use its API-specific option instead:

uv run mindweft-coding-workspace --api-host 0.0.0.0 --api-port 8000
ipconfig getifaddr en0

Open http://<mac-lan-ip>:8000/web/ from a phone on the same network, replacing <mac-lan-ip> with the address printed by ipconfig. Use a trusted local network only; the development auth and browser client are not intended to be exposed publicly.

CLI

Inside the repo:

uv run mindweft run "hello"
uv run mindweft chat --stream "hello with progress"
uv run mindweft-client chat --resume-last
uv run mindweft options
uv run mindweft skills
uv run mindweft capabilities
uv run mindweft threads
uv run mindweft resume
uv run mindweft export --format markdown
uv run mindweft config doctor

Install as a reusable CLI app:

uv tool install '.[voice]'
mindweft-client chat

See the CLI reference for all commands, interactive slash commands, execution option discovery, streaming options, voice modes, and configuration.

Voice

The optional voice extra supports stdin, manual-audio, and passive-audio clients with speech-to-text and text-to-speech integrations. See the voice/client sections in the full reference for provider setup and Linux service helpers.

Peer agents and MCP

Mindweft can delegate work to a local agent wrapper in local-agent-wrapper. The wrapper exposes a coding-agent CLI, such as Pi, OpenCode, or Codex, through a small HTTP task API. Mindweft can use that peer either as:

  • a peer_agent_task tool from the native runtime; or
  • the primary peer_agent backend for a thread.

When the MCP broker is enabled, Mindweft mints short-lived broker sessions so the peer can call approved Mindweft tools without receiving upstream MCP credentials.

Deployment

The repo includes a production-oriented Dockerfile and compose.yaml. A typical Compose deployment sets at least:

MINDWEFT_AUTH_MODE=jwt
MINDWEFT_LLM_PROVIDER=openai
OPENAI_API_KEY=...
MINDWEFT_LOG_FORMAT=json
MINDWEFT_THREAD_DB_PATH=/data/mindweft-threads.db

Then run:

docker compose build
docker compose up -d

compose.yaml binds to 127.0.0.1:8000 by default so a same-host reverse proxy can expose it deliberately.

Documentation

Development

uv run pytest
MINDWEFT_RUN_E2E_TESTS=true uv run pytest -m e2e
uv run ruff check .
uv run ruff format .
uv run basedpyright

To use the tracked pre-commit and pre-push hooks, run once per clone:

./scripts/install-git-hooks.sh

The pre-commit hook runs formatting, lint, and type checks. The pre-push hook runs MINDWEFT_RUN_E2E_TESTS=true uv run pytest before each push.

Repository rules

chore: redact secrets from MCP URL logging

License

Mindweft is licensed under the Apache License 2.0.

Download files

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

Source Distribution

mindweft-0.1.0.tar.gz (634.8 kB view details)

Uploaded Source

Built Distribution

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

mindweft-0.1.0-py3-none-any.whl (460.4 kB view details)

Uploaded Python 3

File details

Details for the file mindweft-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for mindweft-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4b93ebe93f054d3ae53df15b5f474932f397db4c1ce7a90d8e10145943b42f06
MD5 af9acb7af24c670f10e7ef485e6cdb08
BLAKE2b-256 e678ff41a746198d5064e0dc0d9f59907eb2dc559758e2313617528e85e9b1e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for mindweft-0.1.0.tar.gz:

Publisher: release.yml on bebaek/mindweft

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

File details

Details for the file mindweft-0.1.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for mindweft-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4e7267cee387bb42cdde403d07789b372ddf5cbaeefb7f93a4ed45d25c167194
MD5 c2b5fa479f2425b13e93b95e51f7cd43
BLAKE2b-256 67172e8039c74c9f16db835714a8167618701591ff9a4739acbe4698bbe3ad21

See more details on using hashes here.

Provenance

The following attestation bundles were made for mindweft-0.1.0-py3-none-any.whl:

Publisher: release.yml on bebaek/mindweft

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page