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.gitignoreentry 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:
Config File Locations¶
JSAT searches for a config file in this order (first found wins):
- Explicit
--configCLI flag orconfig=SDK argument $JSAT_CONFIGenvironment variable{repo}/.jsat/config.yaml— repo-local (recommended for project-specific settings){repo}/.jsat.yaml— legacy fallback./.jsat/config.yaml— CWD canonical./.jsat.yaml— CWD legacy~/.jsat/config.yaml— global user config (written byjsat init --global)~/.config/jsat/config.yaml— XDG user config/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:
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:
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:
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:
Key Sections Explained¶
graph¶
Controls where the codebase graph is stored.
sqlite— default, zero setup, all data in.jsat/graph/graph.dbneo4j— for teams; supports shared access, complex graph querieslightgraph— 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 withnomic-embed-codeopenai— usestext-embedding-3-smallvia the OpenAI APInone— 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:
For LM Studio or a custom OpenAI-compatible server:
cache¶
Semantic caching: identical or near-identical queries are served from cache without an LLM call.
memory— fast, lost on restartdisk— 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 IDEmode: server— run JSAT as a long-running HTTP MCP server (not yet fully implemented)auth: true— requireJSAT_MCP_TOKENin the request header
ithinking¶
Controls structured planning behavior.
mode: interactive— pauses for human review before executing complex tasksmode: silent— never pauses; plans are generated internally but not shownmode: report-only— always shows the plan but never pauses
gate_level controls how aggressively the framework triggers:
low— triggers on all tasksmedium— triggers on medium+ complexity taskshigh— triggers only on high-complexity tasks
log¶
Controls structlog output.
level: DEBUG— verbose, useful for developmentformat: json— structured JSON logs, useful in CI and for log aggregation toolsfile: /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 aprovider(claude_cli,opencode_cli,bob_cli,codex_cli,ollama,anthropic,openai,openai_compat) and amodelname.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 findingmedium— 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. Whenfalse, messages are sent as typed.mode— when optimization runs:auto— optimize only when the raw prompt is belowmax_context_tokensand the task classifier assigns a non-trivial labelalways— optimize every message unconditionallynever— disable the pipeline (equivalent toenabled: 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 to0to 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, orcritical. 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 of3.5catches 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) toaudit_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 (seeimprovebelow).
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 suggestingjsat improve. Only ever printed when both stdout and stderr are TTYs, so it can never corrupt MCP stdio, pipes, or--jsonoutput.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 repositoryjsat improve --reporttargets. 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:
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 |