Skip to main content

ConversationAdvisor (gnosis)

A CLI for ingesting and analyzing AI agent conversation logs (Claude Code, Codex) into a local SQLite store. Tracks every conversation through a three-stage lifecycle — discovered → imported → analyzed — so the expensive LLM steps (intent classification, pain-point detection) run once and their results are persisted for later inspection.

Features

  • Stateful ingestiongnosis discover walks the default Claude (~/.claude/projects/) and Codex (~/.codex/sessions/) roots, parses every session file, and stores conversations + messages into a SQLite DB. Incremental: re-running only appends new turns.
  • Intent classificationgnosis conversation classify segments a conversation into discrete tasks by classifying each user message along two axes (Type + Lifecycle). New-Task lifecycle entries become task rows.
  • Pain-point analysisgnosis task analyze runs a LangGraph DAG (scanner → classifier → resolver) against each task and persists problems with severity, suggested fix, and message-range evidence.
  • Friction-derived effectiveness — the headline mean_effectiveness metric (and the THS effectiveness weight, shown as the Friction bar) is computed by hla.models.friction_score: the deterministic per-tool effectiveness mean × a confirmed-friction-episode penalty. The deterministic tool scorer is an input to friction, not a separate metric. Per-message effectiveness (the tool component) is still stamped on Tool messages. See docs/effectiveness-metric.md and the friction-analysis section of CLAUDE.md.
  • Idempotent re-runs — every stage skips work that's already cached in the store; --rebuild flags force re-computation when needed.
  • Two output formats — most read-only commands accept --format table|json. JSON output is unconstrained (no truncation) for machine consumption.
  • Two providers — Anthropic (claude-haiku) or Ollama (qwen2.5:3b) for local inference.

Requirements

Installation

uv sync                     # primary path; reads uv.lock
uv sync --extra dev         # adds pytest, black, mypy, ruff, torch
uv sync --extra lint        # just black/ruff/mypy (matches the CI lane)

pip install -e . works too — same [project] section in pyproject.toml. One caveat: the optional embark-code-methods wheel (tree-sitter structure triage for gnosis labs review-current-branch; everything else works without it) lives on the JetBrains package index, which uv resolves automatically via [tool.uv.sources] but plain pip does not:

pip install -e ".[embark]" --extra-index-url https://packages.jetbrains.team/pypi/p/grazi/jetbrains-ai-platform-public/simple

To install the published package from PyPI (base feature set, no repo checkout):

pip install gnosis-air   # or: uv tool install gnosis-air

For the Anthropic provider, drop your key in .env at the repo root or pass it via --key:

echo 'ANTHROPIC_API_KEY=sk-ant-…' > .env

For Ollama:

ollama pull qwen2.5:3b
ollama serve

The SQLite store lives at ~/.local/share/gnosis/gnosis.sqlite3 by default. Override per-invocation via --db-path (on discover/stats) or via the GNOSIS_DB_PATH env var (every command).

Embedding in another application

If you're calling gnosis as a subprocess from another application (an IDE plugin, a desktop app, a CI step), the parent doesn't need to assume uv, pip, or even Python is set up the way the user's interactive shell expects. Use scripts/bootstrap.py to install uv (if missing) and then install gnosis into an isolated uv tool venv. Cross-platform — works on Linux, macOS, and Windows.

import subprocess, sys

# One-time bootstrap. Idempotent — safe to call on every launch.
result = subprocess.run(
    [sys.executable, "scripts/bootstrap.py", "--gnosis-ref", "v0.3.0"],
    capture_output=True, text=True, check=True,
)
gnosis_binary = result.stdout.strip().splitlines()[-1]

# Every subsequent invocation: subprocess the binary directly.
subprocess.run(
    [gnosis_binary, "conversation", "messages", "3", "--task", "22", "--format", "json"],
    env={**os.environ, "GNOSIS_DB_PATH": "/path/parent/controls",
         "ANTHROPIC_API_KEY": "sk-ant-…"},
    capture_output=True, check=True,
)

The bootstrap script:

  • Looks for uv on PATH and at astral's standard install locations (~/.local/bin/uv, etc.).
  • If missing, runs astral's official installer (curl … | sh on Unix; irm … | iex on Windows) — no third-party hosts.
  • Runs uv tool install --python 3.12 git+<gnosis-url>@<ref> to create an isolated venv.
  • Verifies the install by importing gnosis's LLM entry chain in the tool venv, so an incomplete env (e.g. a compiled transitive dep dropped by a partial/proxy-blocked download) fails at bootstrap time with a clear message rather than as a mystery ModuleNotFoundError at runtime.
  • Mirrors everything — uv's output, exit code, resolved path, verification result — to a timestamped log at <tempdir>/gnosis/gnosis-bootstrap__<ts>.log, so a failed install stays inspectable after the subprocess exits.
  • Prints the resolved gnosis binary path to stdout's last line; progress goes to stderr.

Pass --reinstall (alias --force) to force a full rebuild of gnosis and all its dependencies — the repair path when a user's env is left incomplete (uv tool install is otherwise a no-op if gnosis is already present):

subprocess.run([sys.executable, "scripts/bootstrap.py", "--gnosis-ref", "v0.3.0", "--reinstall"], check=True)

The parent should always invoke gnosis with --format json (machine-parseable output) and pass --key / --db-path (or the ANTHROPIC_API_KEY / GNOSIS_DB_PATH env vars) so the embedded gnosis never touches the user's .env or default state path. See python scripts/bootstrap.py --help for the available flags.

CLI Reference

Every command supports -h / --help. The CLI is a Click group; sub-groups (conversation, task) have their own subcommands.

Lifecycle in 30 seconds

gnosis discover                  # 1. ingest all local sessions into the store
gnosis conversation classify 7          # 2. classify intents + extract tasks for conversation #7
gnosis task analyze 7                 # 3. run pain-point analysis on every task in #7
gnosis task show 7              # 4. browse the results

Each step is incremental and persists its output, so step 4 doesn't re-run the LLM. The conversation's status field (visible in gnosis conversation list) reflects how far it's progressed:

Discovered  →  Imported  →  Analyzed
   (1)          (2)           (3)

discover — ingest trajectories into the store

gnosis discover [--extra-folder PATH]... [--db-path PATH]
                [--rebuild | --rebuild-conversation PATH...]
                [--benchmark] [-v]

Scans ~/.claude/projects/ and ~/.codex/sessions/ (plus any --extra-folder paths), parses every session, and upserts conversations + messages into the store. Idempotent — re-running only appends new turns.

Flag Purpose
--extra-folder PATH Additional folder to scan recursively for *.jsonl. Repeatable.
--db-path PATH Override the default DB location. Beats $GNOSIS_DB_PATH.
--rebuild Drop every conversation row first, then re-import. FK cascade clears messages, intents, tasks, problems too.
--rebuild-conversation PATH Scoped rebuild — drop one conversation's row + cascade, then re-ingest it. Repeatable. Mutually exclusive with --rebuild.
--benchmark Print a stage time / tokens / cost report at the end. (Discover doesn't call any LLMs, so tokens are zero — useful for seeing how long the discovery walk vs ingest pass took.)
-v / --verbose Per-call token usage, parser skips, progress bars.
gnosis discover                                       # default roots only
gnosis discover --extra-folder ~/old-sessions/        # plus an archive folder
gnosis discover --rebuild                             # wipe + re-import everything
gnosis discover --rebuild-conversation ~/.claude/projects/.../foo.jsonl
gnosis discover --benchmark                           # include the per-stage report

conversation list — browse the store

gnosis conversation list [--format table|json]

Compact table sorted by stable # identifier. Columns: #, Provider, Title, Path, Project, Status. Read-only — no LLM.

gnosis conversation list
gnosis conversation list --format json

conversation show — full record for one conversation

gnosis conversation show <id-or-path> [--format table|json]

Identifier is the # from list (integer) or the absolute path on disk. Prints every stored field plus the tasks summary.

gnosis conversation show 7
gnosis conversation show /Users/me/.claude/projects/.../uuid.jsonl
gnosis conversation show 7 --format json

conversation classify — segment one or more conversations into tasks

gnosis conversation classify [IDENTIFIER]
                              [--project NAME] [--folder PATH] [--classify-all]
                              [--benchmark]
                              [-p ollama|anthropic] [--key KEY] [-v]

Runs the two-axis intent classifier on every human message in each matched conversation, in chunks of ≤ 4 humans per LLM call. Incremental: humans with a stored intent are skipped. New-Task lifecycle classifications become task rows; the conversation flips to Imported.

Exactly one selector must be set:

Selector Effect
<IDENTIFIER> One conversation, by # (digits) or absolute path.
--project NAME Every conversation whose project column equals NAME.
--folder PATH Every conversation whose path starts with PATH/.
--classify-all Every conversation in the store.

Conditional re-classification wipe. If at least one new intent is saved this run, prior analysis state is invalidated: tasks rows replaced (their analyzed_at/token columns dropped), all problems deleted, last_analysis cleared. On a true no-op re-run (every human already classified), nothing changes — analysis state is preserved.

--benchmark prints a per-conversation time / tokens / cost report at the end.

gnosis conversation classify 7                                       # single by #
gnosis conversation classify /Users/me/.claude/.../uuid.jsonl        # single by path
gnosis conversation classify --project /Users/me/projects/foo        # by project
gnosis conversation classify --folder ~/.claude/projects/            # by folder prefix
gnosis conversation classify --classify-all                          # everything
gnosis conversation classify --classify-all --benchmark

conversation friction — multi-tier inefficiency analysis

gnosis conversation friction <id-or-path>
                              [--rebuild] [--benchmark] [--format table|json]
                              [-p ollama|anthropic] [--key KEY] [-v]

Finds the friction a per-tool-call scan misses — defects the user had to paste back, dissatisfaction loops, blocked stalls, wrong-context requests, output-visibility misses. A deterministic pass (no LLM) surfaces candidate episodes; a single batched LLM call then adjudicates each (real? root cause? wasted turns? one-line remedy). ~$0.02 per conversation on Haiku.

Results persist to the store. Re-running renders the cached verdicts without an LLM call; pass --rebuild to re-detect and re-adjudicate. --format json emits the full payload (episodes + verdicts + a wasted-turn rollup).

gnosis conversation friction 2                 # detect + adjudicate (or render cached)
gnosis conversation friction 2 --benchmark     # + time / tokens / cost
gnosis conversation friction 2 --format json   # structured payload
gnosis conversation friction 2 --rebuild       # force re-analysis

task list — browse one conversation's tasks

gnosis task list <id-or-path> [--format table|json]

Compact table: #, Status (not analyzed / analyzed), Type, Position, Title. Read-only.

gnosis task list 7
gnosis task list 7 --format json

task show — detailed task view

gnosis task show <id-or-path> [--task N] [--format table|json]

Without --task: every task is printed in full detail. With --task N: just that one (errors if out of range).

Each task includes: intent segments (text + Type + Lifecycle), message-range start → end, start_time / end_time from the source JSONL, per-type step counts (user, agent, tool), analyzed_at and tokens spent (when analyzed), and any persisted problems with their severity / fix / analysis. Read-only.

gnosis task show 7
gnosis task show 7 --task 2
gnosis task show 7 --format json

task analyze — find pain points in a conversation

gnosis task analyze <id-or-path> [--task N] [--rebuild] [--benchmark]
                    [-p ollama|anthropic] [--key KEY] [-v]

Runs the LangGraph pain-point pipeline against each task in a conversation. Per-task idempotent — tasks already analyzed (analyzed_at stamped) are rendered from the store without re-running the LLM. With --task N it scopes to one task.

--rebuild clears problems + analyzed_at for the scope (whole conversation or single task) up front, then re-analyzes everything. Use after fixing prompt/scoring code or when you want a fresh read.

--benchmark prints a per-task time / tokens / cost report at the end.

On success: problems persisted, tasks.analyzed_at / input_tokens / output_tokens stamped per task, conversations.last_analysis updated → status flips to Analyzed.

gnosis task analyze 7                                   # analyze unanalyzed tasks in #7
gnosis task analyze 7 --task 2                          # only task #2 (cached if already done)
gnosis task analyze 7 --rebuild                         # force re-analysis of every task
gnosis task analyze 7 --task 2 --rebuild                # force re-analysis of just task #2
gnosis task analyze 7 --benchmark                       # add the per-stage report

stats — store summary

gnosis stats [--db-path PATH]

Prints: total conversations, distinct projects, median human/agent/tool messages per conversation.

gnosis stats
GNOSIS_DB_PATH=/tmp/scratch.sqlite3 gnosis stats

score and intents (legacy, file-based)

These two haven't been migrated to the store. They take a session file path (or directory) directly.

gnosis score   <session.jsonl> [-p anthropic|ollama] [--key KEY] [-v]
gnosis intents <session.jsonl> [-p anthropic|ollama] [--key KEY] [-v]

score returns one of Bad / Ok / Good for the whole conversation. intents prints the full per-message intent table.


Architecture

High-level data flow

The pipeline is session file → parsed messages → SQLite store → on-demand LLM stages. The store is the single source of truth for everything except the freshly-parsed BaseMessage list during discover.

flowchart TB
    classDef store fill:#dde,stroke:#666
    classDef agent fill:#fdd,stroke:#666

    subgraph Files["~/.claude/projects/, ~/.codex/sessions/, --extra-folder"]
        SF[".jsonl files"]
    end

    SF --> Disc

    subgraph Layers["src/"]
        direction TB
        Disc["discovery/<br/>find trajectory files<br/>per provider"]
        Pars["parsers/<br/>JSONL → list[BaseMessage]<br/>(Claude / Codex)"]
        HLA["hla/<br/>conversation_outline<br/>(skeleton, chunks, IDE-strip)"]
        Agents["agents/<br/>intent_analyzer<br/>conversation_optimizer<br/>user_satisfaction"]
        Comp["analyzers/<br/>comprehensive_scan/<br/>(LangGraph DAG)"]
        Cmds["commands/<br/>one file per CLI verb"]
        Store[("storage/<br/>SQLite store<br/>~/.local/share/gnosis/<br/>gnosis.sqlite3")]
    end

    Disc --> Pars
    Pars --> HLA
    HLA --> Agents
    Agents --> Comp
    Cmds <--> Store
    Cmds --> Agents
    Pars --> Store
    Store:::store
    Agents:::agent
    Comp:::agent

    Store -. read .-> CLI["gnosis CLI<br/>(Click)"]
    CLI --> Cmds

Layer rules (load-bearing — see CLAUDE.md for the full list):

  • commands/ is the only layer the CLI talks to.
  • agents/ is where every LLM call lives. Never imports from parsers/ or discovery/ — agents work on already-parsed BaseMessage lists.
  • hla/ (no-LLM data shaping) and agents/ (LLM) are siblings.
  • storage/ is provider-agnostic; everything in commands/, agents/, and hla/ reads/writes through its helpers.

SQLite schema

Five tables, all in SQLite STRICT mode. The lifecycle is encoded in the FK cascades.

erDiagram
    conversations ||--o{ messages : "cascades on delete"
    messages ||--o| intents : "(path, position) cascades"
    intents ||--o| tasks : "(path, position) cascades"
    conversations ||--o{ problems : "cascades on delete"

    conversations {
        INTEGER id "stable # identifier"
        TEXT path PK "absolute trajectory path"
        TEXT provider "claude | codex"
        TEXT title
        TEXT project
        TEXT created_at
        TEXT last_updated_at
        TEXT first_ingested_at
        TEXT last_ingested_at
        TEXT last_task_analysis "stamped by conversations classify"
        TEXT last_analysis "stamped by analyze"
    }
    messages {
        TEXT conversation_path PK,FK
        INTEGER position PK "0-based parser ordinal"
        TEXT type "human | agent | tool"
        TEXT uuid "stable for claude"
        TEXT timestamp "from raw JSONL entry"
        TEXT payload "pydantic model_dump_json"
    }
    intents {
        TEXT conversation_path PK,FK
        INTEGER position PK,FK "→ messages.position"
        TEXT title
        TEXT segments_json "JSON list[{text, type, lifecycle}]"
        TEXT classified_at
    }
    tasks {
        TEXT conversation_path PK,FK
        INTEGER number PK "1-indexed per conversation"
        INTEGER position UK,FK "→ intents.position"
        TEXT type
        TEXT title
        TEXT analyzed_at "NULL = classified, NOT NULL = analyzed"
        INTEGER input_tokens
        INTEGER output_tokens
    }
    problems {
        TEXT conversation_path FK
        INTEGER task_number "FK by convention; NULL for fallback runs"
        TEXT type
        INTEGER relevant_message_range_start
        INTEGER relevant_message_range_end
        REAL severity
        TEXT description
        TEXT suggested_fix
        TEXT analysis
        TEXT created_at
    }

The cascade chain: deleting a conversation row → cascades to its messages and problems rows → which cascades to intents → which cascades to tasks. This is what makes discover --rebuild a clean wipe and what keeps --rebuild-conversation <path> precisely scoped.

Per-conversation status derivation

Computed in storage/conversations.py:compute_status from two signals:

stateDiagram-v2
    [*] --> Discovered : gnosis discover
    Discovered --> Imported : gnosis conversation classify
    Imported --> Analyzed : gnosis task analyze
    Analyzed --> Imported : conversation classify (invalidates analysis)
    Imported --> Imported : conversation classify (incremental)
    Analyzed --> Analyzed : analyze (cached re-render)
    Analyzed --> Analyzed : analyze --rebuild
  • Discoveredtasks table is empty for this conversation.
  • Imported — at least one task row, last_analysis IS NULL.
  • Analyzedlast_analysis IS NOT NULL.

Per-task status is independent and shown in task list / task show:

  • not analyzed — task row exists, analyzed_at IS NULL.
  • analyzedanalyzed_at IS NOT NULL (problems persisted, tokens recorded).

discover flow

flowchart TD
    cli["gnosis discover [--extra-folder PATH]... [--rebuild | --rebuild-conversation PATH]..."]
    cli --> resolveDB["resolve DB path<br/>(--db-path > $GNOSIS_DB_PATH > default)"]
    resolveDB --> openDB["open + migrate schema<br/>(CREATE TABLE IF NOT EXISTS + idempotent ALTER TABLE)"]
    openDB --> rebuild{--rebuild?}
    rebuild -- yes --> wipeAll["DELETE FROM conversations<br/>(cascades to all tables)"]
    rebuild -- no --> rebuildOne{--rebuild-conversation?}
    rebuildOne -- yes --> wipeOne["DELETE FROM conversations<br/>WHERE path IN (...) (cascades)"]
    rebuildOne -- no --> walk
    wipeAll --> walk
    wipeOne --> walk
    walk["discover_trajectories(project=None)<br/>+ glob each --extra-folder"]
    walk --> perTraj[for each trajectory]
    perTraj --> parse["read + parsers.get_messages(content)<br/>list[BaseMessage] with timestamps"]
    parse --> fill["hla.fill_tool_success(msgs[existing_count:])<br/>(sentence-transformer; cached centroid)"]
    fill --> upsert["upsert conversation + append messages<br/>(BEGIN IMMEDIATE; idempotent)"]
    upsert --> uuidCheck{first N stored uuids<br/>match parsed prefix?<br/>(claude only)}
    uuidCheck -- yes --> next[next trajectory]
    uuidCheck -- no --> skip["skip with warning<br/>(tree branch divergence)"]
    skip --> next
    next --> done(["summary line:<br/>N scanned, M new conversations,<br/>K new messages"])

conversation classify flow

flowchart TD
    cli["gnosis conversation classify (one selector required)"]
    cli --> resolve["find_conversation_by_identifier<br/>(digits → id, else path)"]
    resolve --> miss{found?}
    miss -- no --> err1["Error → stderr"]
    miss -- yes --> load["load_messages + load_intents"]
    load --> diff["new_positions = {all humans} − {classified}"]
    diff --> any{new_positions empty?}
    any -- yes --> stamp
    any -- no --> chunk["create_messages_skeleton_outline<br/>chunk_messages(max_humans=4)"]
    chunk --> filter["keep chunks containing ≥1 new human"]
    filter --> llm["per chunk:<br/>analyze_intents_from_outline<br/>(retry once on missing indexes)"]
    llm --> persist["save_intents (INSERT OR IGNORE)<br/>only new positions"]
    persist --> stamp
    stamp["compute task boundaries<br/>save_tasks (DELETE + INSERT)<br/>set_last_task_analysis(now)<br/>delete_problems(path)<br/>UPDATE last_analysis = NULL"]
    stamp --> summary["summary:<br/>N tasks identified<br/>+ note if prior analysis was cleared"]

task analyze flow

flowchart TD
    cli["gnosis task analyze &lt;id-or-path&gt; [--task N] [--rebuild] [--benchmark]"]
    cli --> guard["check: conversation exists,<br/>last_task_analysis IS NOT NULL"]
    guard --> scope{--task N?}
    scope -- yes --> single["scope = [task N]"]
    scope -- no --> all["scope = every task"]
    single --> rebuildQ
    all --> rebuildQ
    rebuildQ{--rebuild?}
    rebuildQ -- yes --> wipe["upfront wipe in scope:<br/>delete_problems(...) +<br/>UPDATE tasks SET analyzed_at=NULL"]
    rebuildQ -- no --> part["partition scope<br/>by analyzed_at IS NULL/NOT NULL"]
    wipe --> part2["to_analyze = scope<br/>cached = []"]
    part --> loop
    part2 --> loop
    loop[for each task in to_analyze]
    loop --> benchmark["with benchmark(task #N) as section:<br/>find_problems(msgs[start:end])<br/>(comprehensive_scan LangGraph:<br/>Scanner → Classifier×N → Resolver)"]
    benchmark --> save["BEGIN IMMEDIATE:<br/>delete_problems(path, task=N)<br/>save_problems(...)<br/>mark_task_analyzed(N, tokens, now)"]
    save --> loop
    loop -- done --> render["load_problems(path)<br/>reconstruct full TaskAnalysis from cached + new<br/>+ stored task ranges<br/>compute IQC / per-task TQC<br/>print report + benchmark"]

find_problems invokes the LangGraph DAG in analyzers/comprehensive_scan/ — a pre-scanner node first stamps anchor-driven effectiveness scores on each Tool / Agent message (see docs/effectiveness-metric.md); a cost-scanner stamps cost_effectiveness on each Human; then scanner finds suspect ranges, classifier verifies each via a sub-agent with get_messages_by_range / get_detailed_message tools, and resolver assigns severity + fix. See CLAUDE.md for the full walkthrough.

Project structure

.
├── src/
│   ├── gnosis.py                          # Click CLI entry point
│   ├── main.py                            # legacy argparse entry (discover/show)
│   ├── llm.py                             # provider abstraction + llm_invoke
│   ├── utils.py
│   ├── tool_output_classifier.py          # sentence-transformer for tool success/failure
│   ├── pattern_scanner.py                 # heuristic helpers (unused; pending cleanup)
│   ├── commands/                          # one file per CLI verb
│   │   ├── analyze.py, conversations.py,
│   │   │ discover.py, intents.py, score.py,
│   │   │ show.py, stats.py, tasks.py
│   │   └── runner.py                      # iter_session_files + run_over_path
│   ├── parsers/                           # JSONL → list[BaseMessage]
│   │   ├── base.py, claude.py, codex.py, messages.py
│   ├── discovery/                         # find session files per provider
│   ├── storage/                           # SQLite store
│   │   ├── db.py                          # connection, schema bootstrap, migrations
│   │   └── conversations.py               # CRUD + StoredTask/StoredIntent/StoredProblem
│   ├── hla/                               # non-LLM data shaping
│   │   ├── conversation_outline.py        # outline, skeleton, chunking, ide-block strip
│   │   ├── benchmark.py                   # BenchmarkSection + UsageTracker
│   │   └── models.py                      # Problem, TaskAnalysis, ByTaskAnalysisResult
│   ├── agents/                            # LLM-driven analyzers
│   │   ├── intent_analyzer.py             # two-axis classification
│   │   ├── conversation_optimizer.py      # find_problems (entry to comprehensive_scan)
│   │   └── user_satisfaction.py
│   ├── analyzers/comprehensive_scan/      # LangGraph DAG: scanner → classifier → resolver
│   ├── analysis_tools/                    # LangChain tools used by sub-agents
│   └── contracts/                         # shared types (IntentType, TaskBoundary, etc.)
├── data/sessions/                         # bundled sample conversations
├── experiments/                           # exploratory notebooks (not tests)
└── .github/workflows/lint.yml             # black + ruff + mypy on every PR

LLM providers

LLMConfig in src/llm.py carries provider, model, and per-million-token pricing. Two presets:

Preset Provider Model
LLMConfig.claude_haiku_4_5_20251001() Anthropic claude-haiku-4-5-20251001
LLMConfig.ollama_qwen_2_5__3b() Ollama qwen2.5:3b

llm_invoke() is the single entry point — it builds the langchain client, runs structured-output inference, wires the UsageTracker callback so per-task tokens flow into the active BenchmarkSection, and prints per-call cost.

Download files

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

Source Distribution

gnosis_air-0.0.3.tar.gz (841.1 kB view details)

Uploaded Source

Built Distribution

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

gnosis_air-0.0.3-py3-none-any.whl (842.9 kB view details)

Uploaded Python 3

File details

Details for the file gnosis_air-0.0.3.tar.gz.

File metadata

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

File hashes

Hashes for gnosis_air-0.0.3.tar.gz
Algorithm Hash digest
SHA256 ff0a4af42472b9012bb300cdeacbc432e3c7e7c3ea71bf16f50350e5c1ff4e92
MD5 f0b945c1c485829503d6e9049ea67f94
BLAKE2b-256 4757bd7285b6dfc13b71e28e92bfad7497e1f57f83efbd51d87e6e96dd8b119d

See more details on using hashes here.

Provenance

The following attestation bundles were made for gnosis_air-0.0.3.tar.gz:

Publisher: publish-pypi.yml on JetBrains/air-trajectory-analysis

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

File details

Details for the file gnosis_air-0.0.3-py3-none-any.whl.

File metadata

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

File hashes

Hashes for gnosis_air-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5d8e0c99edd4428931cc0d3c4039e98cd931dcb94adda52d831a7a56556aed4e
MD5 24af1465d30691de7c7426efaa6b67ab
BLAKE2b-256 a014de8f8756f001f27ff0c2bcbbdc3cad93f252f2fdde2a582eed359f2e0149

See more details on using hashes here.

Provenance

The following attestation bundles were made for gnosis_air-0.0.3-py3-none-any.whl:

Publisher: publish-pypi.yml on JetBrains/air-trajectory-analysis

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