Skip to content

Configuration

Data Storage vs Config File

JSAT separates runtime state from project config:

  • Runtime state (graph database, vector store, cache, prompt history) lives in a global per-repo directory at ~/.jsat/<hash12>/ by default — completely outside your git working tree, no .gitignore entry needed.
  • Config file (.jsat/config.yaml) is optional and repo-local. It holds only project-specific settings like languages to index, AI provider preference, and review models.

Data directory resolution order

Priority Location When
1 $JSAT_DATA_DIR env var set (CI, Docker, custom paths)
2 {repo}/.jsat/ already exists on disk (backward compat)
3 ~/.jsat/<sha1_12>/ default — global store, repo-isolated

The hash is the first 12 hex characters of SHA-1 over the resolved repo path, so the same repo always maps to the same directory regardless of CWD or symlinks.

To find where JSAT is storing data for the current repo:

jsat doctor           # shows jsat_dir in the output

Config File Locations

JSAT searches for a config file in this order (first found wins):

  1. Explicit --config CLI flag or config= SDK argument
  2. $JSAT_CONFIG environment variable
  3. {repo}/.jsat/config.yamlrepo-local (recommended for project-specific settings)
  4. {repo}/.jsat.yaml — legacy fallback
  5. ./.jsat/config.yaml — CWD canonical
  6. ./.jsat.yaml — CWD legacy
  7. ~/.jsat/config.yamlglobal user config (written by jsat init --global)
  8. ~/.config/jsat/config.yaml — XDG user config
  9. /etc/jsat/config.yaml — system global

If no config file is found, JSAT uses built-in defaults and auto-detects everything.

Generate a Starter Config

# Per-repo config (just this project):
jsat init --profile solo
jsat init --profile team
jsat init --profile ci
jsat init --profile raspberry-pi

# Global config (applies to all projects on this machine):
jsat init --global --profile solo

--global writes to ~/.jsat/config.yaml. Any repo without its own .jsat/config.yaml picks this up automatically.


Full Config Reference

version: "1"
project_name: my-project
project_root: "."

# ── Graph backend ──────────────────────────────────────────────────────────────
graph:
  backend: sqlite               # "sqlite" | "neo4j" | "lightgraph"
  path: .jsat/graph/graph.db    # resolved to data dir at runtime (see Data Storage above)
  remote_uri: null              # Neo4j: "bolt://localhost:7687"
  username: neo4j               # Neo4j username
  password_env: NEO4J_PASSWORD  # env var holding the Neo4j password
  max_nodes: 5000000
  max_edges: 20000000

# ── Embeddings ─────────────────────────────────────────────────────────────────
# NOT YET WIRED IN. The embedding backends and vector stores below are
# implemented and unit-tested, but no part of indexing or querying calls them
# yet: all retrieval in JSAT today (query, knowledge, the prompt optimizer's
# context and few-shot agents) is keyword/substring/Jaccard based, not vector
# based. These settings are accepted and validated, and changing them has no
# effect on results. Semantic retrieval is planned; until then treat this
# block as reserved.
embeddings:
  provider: local               # "local" | "openai" | "huggingface" | "none"
  model: nomic-embed-code       # local model name or OpenAI model
  api_key_env: OPENAI_API_KEY   # env var for embedding API key
  dimensions: 768
  batch_size: 64

  vector_store:
    backend: sqlite-vss         # "sqlite-vss" | "qdrant" | "pgvector"
    path: .jsat/vectors/        # local vector store directory
    remote_uri: null            # Qdrant: "http://localhost:6333"
    collection: jsat_code
    api_key_env: QDRANT_API_KEY

# ── AI provider ────────────────────────────────────────────────────────────────
ai:
  provider: ollama              # also: anthropic, openai, openai_compat, claude_cli, opencode_cli, bob_cli, codex_cli, none
  model: null                   # explicit model; native CLIs choose their own when null
  api_key_env: null             # env var name, e.g. ANTHROPIC_API_KEY (read automatically)
  base_url: null                # for openai_compat (LM Studio, Gemini, custom)
  max_tokens: 8192
  temperature: 0.1
  timeout_seconds: 120
  retry_attempts: 3

# ── Cache ──────────────────────────────────────────────────────────────────────
cache:
  enabled: true
  backend: memory               # "memory" | "disk" | "redis"
  redis_uri: null               # "redis://localhost:6379"
  ttl_seconds: 3600
  max_memory_mb: 512
  disk_path: .jsat/cache/

# ── Indexer ────────────────────────────────────────────────────────────────────
indexer:
  # Defaults to every language JSAT has a parser for. A language whose
  # optional tree-sitter grammar is not installed contributes no nodes for
  # those files rather than failing the index, so listing them all is safe on
  # a core-only install. Narrow this list only to deliberately skip a
  # language — a shorter list silently ignores those files.
  languages:
    - python
    - javascript
    - typescript
    - go
    - java
    - ruby
    - rust
  exclude_patterns:
    - .git
    - .claude           # excludes agent worktrees created by Claude Code
    - node_modules
    - __pycache__
    - .venv
    - vendor
    - dist
    - build
  incremental: true             # only re-index changed files
  git_hooks: true               # auto-index on git commit
  max_file_size_kb: 500
  follow_symlinks: false
  embedding_batch_size: 64

# ── MCP server ─────────────────────────────────────────────────────────────────
mcp:
  mode: embedded                # "embedded" | "server"
  port: 8765
  auth: false                   # require JSAT_MCP_TOKEN header
  auth_token_env: JSAT_MCP_TOKEN

# ── IThinking ─────────────────────────────────────────────────────────────────
ithinking:
  enabled: true
  mode: interactive             # "interactive" | "silent" | "report-only"
  prompt_review: true           # pause for human review of the plan
  decomposition_review: true    # pause at decomposition step
  assumption_audit: true        # run assumption audit before execution
  local_first: true             # prefer local computation over LLM when possible
  gate_level: medium            # "low" | "medium" | "high"
  reflection: true              # generate phase 6 reflection
  knowledge_update: true        # update knowledge base after tasks

# ── Logging ────────────────────────────────────────────────────────────────────
log:
  level: INFO                   # "DEBUG" | "INFO" | "WARNING" | "ERROR"
  format: text                  # "text" | "json"
  file: null                    # optional log file path

# ── Skills ─────────────────────────────────────────────────────────────────────
skills:
  dir: skills/
  auto_discover: true
  override_builtins: true
  clusters: {}

# ── Review ─────────────────────────────────────────────────────────────────────
review:
  models:
    - {provider: claude_cli, model: claude-sonnet-4-6}
    - {provider: ollama, model: qwen2.5:0.5b}
  parallel_timeout_seconds: 90   # wall-clock deadline per model; exceeded models are skipped
  min_confidence: medium          # "low" | "medium" | "high"

# ── Prompt Optimizer ───────────────────────────────────────────────────────────
prompt:
  enabled: true                    # auto-optimize all shell messages
  mode: auto                       # "auto" | "always" | "never"
  max_context_tokens: 8192         # max tokens allocated to injected graph context
  few_shot_k: 3                    # number of few-shot examples to inject
  compress_threshold: 6000         # enable token compression above this count
  context_depth: 2                 # BFS depth for graph context injection
  cot_tasks: [debug, plan, security]  # task types that get chain-of-thought appended
  history_path: .jsat/prompt-history.jsonl
  history_max_entries: 10000

# ── Security ───────────────────────────────────────────────────────────────────
security:
  cvss_threshold: medium          # "low" | "medium" | "high" | "critical"
  secret_entropy_threshold: 3.5   # Shannon entropy threshold for secret detection

# ── Privacy ────────────────────────────────────────────────────────────────────
privacy:
  hash_pii: false                 # hash PII values before storing in the graph
  no_telemetry: false             # true also disables self-improvement capture
  audit_log: false                # write an audit log of all JSAT operations
  audit_log_path: .jsat/audit.log

# ── Self-improvement (see `jsat improve`) ──────────────────────────────────────
improve:
  enabled: true                   # record friction JSAT hits in ITSELF (local file only)
  nudge: true                     # hint to run `jsat improve` when an issue recurs
  nudge_threshold: 3              # occurrences of one issue before the hint appears
  nudge_cooldown_s: 86400         # minimum seconds between hints (24h)
  max_signals: 5000               # signal log line cap before rotation
  max_clusters: 500               # issue clusters retained
  github_repo: iamjpsonkar/JaySoft-AI_Tools   # target for --report

Profiles

solo — Individual Developer

Good default for a single developer on a laptop. Uses SQLite (no services required) and Ollama for local AI. Embeddings with nomic-embed-code.

version: "1"
project_name: my-project

graph:
  backend: sqlite

embeddings:
  provider: local
  model: nomic-embed-code
  vector_store:
    backend: sqlite-vss

ai:
  provider: ollama
  model: qwen2.5:0.5b          # exact tag; JSAT never guesses one

cache:
  backend: memory

ithinking:
  mode: interactive
  gate_level: medium

Run:

jsat init --profile solo

team — Engineering Team

For teams with shared infrastructure. Uses Neo4j for the graph, Qdrant for vector search, Redis for caching, and the Anthropic API for AI.

version: "1"
project_name: my-project

graph:
  backend: neo4j
  remote_uri: bolt://localhost:7687
  password_env: NEO4J_PASSWORD

embeddings:
  provider: openai
  model: text-embedding-3-small
  vector_store:
    backend: qdrant
    remote_uri: http://localhost:6333

ai:
  provider: anthropic
  model: claude-sonnet-4-6

cache:
  backend: redis
  redis_uri: redis://localhost:6379

ithinking:
  mode: interactive
  gate_level: high

Run:

jsat init --profile team

Requires pip install jsat[team] and Neo4j, Qdrant, and Redis running locally or in your infrastructure.


ci — Continuous Integration

For CI pipelines. No AI calls, memory-only cache, JSON log format for structured log ingestion, IThinking disabled.

version: "1"
project_name: my-project

graph:
  backend: sqlite

embeddings:
  provider: none

ai:
  provider: none

cache:
  backend: memory

ithinking:
  enabled: false
  mode: silent

log:
  level: WARNING
  format: json

Run:

jsat init --profile ci

When CI=true is set in the environment, JSAT automatically applies these overrides even without a config file.


raspberry-pi — Low-RAM ARM

For ARM devices with limited RAM (Raspberry Pi, older Apple M-series, similar). Selects Ollama but no specific model — JSAT never guesses one — plus smaller embedding batches (8), a 100 KB file cap, and the disk cache. Choose a model that fits your RAM with jsat ai use ollama --model <tag>.

version: "1"
project_name: my-project

graph:
  backend: sqlite

embeddings:
  provider: local
  model: nomic-embed-code
  dimensions: 384
  batch_size: 8
  vector_store:
    backend: sqlite-vss

ai:
  provider: ollama
  model: qwen2.5:0.5b

cache:
  backend: disk

indexer:
  embedding_batch_size: 8
  max_file_size_kb: 100

ithinking:
  mode: silent
  gate_level: low

Run:

jsat init --profile raspberry-pi

Key Sections Explained

graph

Controls where the codebase graph is stored.

  • sqlite — default, zero setup, all data in .jsat/graph/graph.db
  • neo4j — for teams; supports shared access, complex graph queries
  • lightgraph — in-memory, for testing only

For Neo4j:

graph:
  backend: neo4j
  remote_uri: bolt://localhost:7687
  username: neo4j
  password_env: NEO4J_PASSWORD   # read from env at runtime

Never put the Neo4j password directly in the config file.


embeddings

Controls how code is embedded for semantic search.

  • local — uses Ollama to embed locally with nomic-embed-code
  • openai — uses text-embedding-3-small via the OpenAI API
  • none — skips embedding (no semantic search, graph queries only)

For CI or low-resource environments, set provider: none to skip embedding entirely.


ai

Controls which AI model answers natural language queries.

Do not put API keys here. Use environment variables:

export ANTHROPIC_API_KEY=sk-ant-...
export OPENAI_API_KEY=sk-...
export GEMINI_API_KEY=...

For LM Studio or a custom OpenAI-compatible server:

ai:
  provider: openai_compat
  model: <loaded-model-id>
  base_url: http://localhost:1234/v1

cache

Semantic caching: identical or near-identical queries are served from cache without an LLM call.

  • memory — fast, lost on restart
  • disk — persists across restarts, stored in .jsat/cache/
  • redis — shared cache for teams

Cache lookups key on an exact (query, context_hash) pair. Entries record the source files they depend on, so invalidate_for_files drops just the answers a changed file could have affected.


mcp

Controls the MCP server used by Claude Code and Cursor.

  • mode: embedded — default; the MCP server runs as a subprocess started by the IDE
  • mode: server — run JSAT as a long-running HTTP MCP server (not yet fully implemented)
  • auth: true — require JSAT_MCP_TOKEN in the request header

ithinking

Controls structured planning behavior.

  • mode: interactive — pauses for human review before executing complex tasks
  • mode: silent — never pauses; plans are generated internally but not shown
  • mode: report-only — always shows the plan but never pauses

gate_level controls how aggressively the framework triggers:

  • low — triggers on all tasks
  • medium — triggers on medium+ complexity tasks
  • high — triggers only on high-complexity tasks

log

Controls structlog output.

  • level: DEBUG — verbose, useful for development
  • format: json — structured JSON logs, useful in CI and for log aggregation tools
  • file: /var/log/jsat.log — additionally write logs to a file

review

Controls multi-model parallel code review (Tool 9 — MultiModelReview).

  • models — list of provider/model pairs to dispatch the diff to simultaneously. Each entry must specify a provider (claude_cli, opencode_cli, bob_cli, codex_cli, ollama, anthropic, openai, openai_compat) and a model name.
  • parallel_timeout_seconds — wall-clock deadline applied to every model dispatch. Models that exceed this are skipped; their timeout is recorded as a warning in the review output.
  • min_confidence — controls which findings are surfaced:
  • low — any single model's finding
  • medium — confirmed by 2 or more models (default)
  • high — confirmed by all configured models

Do not put API keys in the models list. Keys are read from environment variables as usual (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.).


prompt

Controls the 7-stage prompt optimization pipeline. Auto-optimization rewrites every shell message before sending it to the AI — injecting codebase context, constraints, few-shot examples, and model-specific formatting.

  • enabled: true — turn auto-optimization on or off globally. When false, messages are sent as typed.
  • mode — when optimization runs:
  • auto — optimize only when the raw prompt is below max_context_tokens and the task classifier assigns a non-trivial label
  • always — optimize every message unconditionally
  • never — disable the pipeline (equivalent to enabled: false)
  • max_context_tokens — maximum tokens that can be consumed by injected graph context (stage 2). Larger values inject more codebase context but increase LLM cost.
  • few_shot_k — number of past prompt/response pairs to inject as few-shot examples (stage 4). Set to 0 to disable few-shot injection.
  • compress_threshold — if the assembled prompt exceeds this token count, stage 7 (token compression) activates. Lower values compress more aggressively; higher values leave prompts unchanged unless they are very large.
  • context_depth — BFS depth used when traversing the codebase graph for context injection. Depth 1 includes only direct neighbors; depth 2 includes neighbors-of-neighbors. Higher values surface more context but increase token usage.
  • cot_tasks — list of task types that automatically get chain-of-thought appended. Recognized values: debug, plan, security, review, refactor, code_gen, test, question.
  • history_path — JSONL file where every prompt/response pair is appended for future few-shot retrieval.
  • history_max_entries — maximum entries kept in the history file. Older entries are evicted when this limit is reached.

Set enabled: false or mode: never in the ci profile to skip optimization in pipelines where deterministic, unmodified prompts are required.


security

Controls thresholds for the SecurityReview tool.

  • cvss_threshold — minimum CVSS severity level to report in dependency CVE scans: low, medium, high, or critical. Findings below this threshold are suppressed.
  • secret_entropy_threshold — Shannon entropy value above which a string literal is flagged as a potential hardcoded secret. The default of 3.5 catches most API keys, tokens, and base64-encoded values while reducing false positives on normal strings. Lower values increase sensitivity; higher values reduce noise.

privacy

Controls how JSAT handles potentially sensitive data in the graph and logs.

  • hash_pii: true — before storing any value extracted from source code that matches a PII pattern (email addresses, phone numbers, national IDs), JSAT replaces the raw value with a SHA-256 hash. This prevents PII from being stored in the graph or sent to an LLM.
  • audit_log: true — write a structured audit log of every JSAT operation (index, query, review, knowledge write, MCP tool call) to audit_log_path. Each entry includes a timestamp, operation type, user identity (if available), and a summary of inputs/outputs with sensitive values redacted.
  • audit_log_path — path to the audit log file (relative to repo root). Default: .jsat/audit.log.

Neither setting is enabled by default. Enable both in regulated environments or wherever a record of AI-assisted operations is required for compliance.

  • no_telemetry: true — also disables self-improvement capture (see improve below).

improve

Controls the self-improvement loop behind jsat improve. JSAT records friction it hits in itself so it can later propose a fix to its own source.

  • enabled: true (default) — record signals to a local file. Capture is JSAT-internal-only: JSAT's own stack frames (as paths relative to the package), exception type names, tool names, versions, and config keys. Anything referencing your code, paths, identifiers, or queries is dropped, not redacted, and every record is re-checked against machine identifiers, secret patterns, and environment-variable values before being written.
  • nudge: true — after a command that produced a signal, print one line suggesting jsat improve. Only ever printed when both stdout and stderr are TTYs, so it can never corrupt MCP stdio, pipes, or --json output.
  • nudge_threshold: 3 — how many times one issue must recur before the hint appears.
  • nudge_cooldown_s: 86400 — minimum interval between hints; any single issue is nudged at most three times ever.
  • max_signals / max_clusters — retention caps; the signal log rotates and the least significant clusters are evicted.
  • github_repo — the repository jsat improve --report targets. Change it if you maintain a fork.

Nothing is transmitted anywhere by capture itself. --report opens a pre-filled GitHub issue in your browser, which you read and submit yourself. JSAT never modifies its own installed files — a generated patch is validated against a throwaway copy and remains inert data until a human merges it.

Three independent kill switches, any of which disables capture entirely:

export JSAT_NO_IMPROVE=1
improve:
  enabled: false
privacy:
  no_telemetry: true

Capture is also disabled automatically whenever CI is set.

Data lives in ~/.jsat/improve/ — deliberately not the per-repo data directory, which can resolve to {repo}/.jsat/ inside your private codebase.


Environment Variables

All secrets should be passed via environment variables, never stored in config:

Variable Purpose
JSAT_CONFIG Override config file path
JSAT_DATA_DIR Override data directory (graph, cache, vectors). Useful in CI or Docker
JSAT_RUNTIME_DIR Override managed AI-client lifecycle records (default ~/.jsat/runtime/)
JSAT_NO_IMPROVE If set, disables self-improvement signal capture and the nudge entirely
JSAT_IMPROVE_DIR Override the self-improvement store (default ~/.jsat/improve/)
JSAT_SESSIONS_DIR Override where skill sessions are written (default ~/.jsat/sessions/)
ANTHROPIC_API_KEY Anthropic API key
OPENAI_API_KEY OpenAI API key
GEMINI_API_KEY Gemini API key (GOOGLE_API_KEY also accepted)
NEO4J_PASSWORD Neo4j password (key name configurable via password_env)
QDRANT_API_KEY Qdrant API key (key name configurable via api_key_env)
JSAT_MCP_TOKEN MCP server auth token
JSAT_AI_PROVIDER Override AI provider for this process (set automatically by jsat connect)
CI If true/1/yes, forces CI profile overrides