CLI section:
- Intro updated to mention startup dashboard and Rich polish
- Data In: added semantica watch examples; removed --watch flag from ingest
(watch is now its own command)
- Developer Tools: new subsection covering init, doctor, changelog, shell,
info with representative examples
What's New in v0.5.0:
- Added Modern CLI Experience subsection listing all 11 improvements:
startup dashboard, grouped help, doctor, init, watch, changelog, shell,
progress bars, elapsed timing, error cards, Windows UTF-8 fix
In TOML, declaring [project.urls] inside the [project] block causes all
subsequent key-value pairs (including dependencies = [...]) to be parsed
as project.urls.* keys, producing:
ValueError: invalid pyproject.toml config: project.urls.dependencies
must be string
Fix: move [project.urls] to after the dependencies array closes and before
[project.optional-dependencies], which is the correct TOML position for a
sub-table of [project].
Elapsed timing
- CLIContext._start records time.perf_counter() at context creation
- _ok() appends elapsed seconds to every success message automatically
Structured error cards
- _show_error_card() renders a red-bordered Rich Panel with title, detail,
and an actionable hint line
- _ERROR_HINTS maps common exception types to fix suggestions
- _run_with_error_handling() now routes all errors through the card renderer
instead of raising plain click.ClickException
Rich progress bars
- kg build: per-source Progress bar (SpinnerColumn + BarColumn +
MofNCompleteColumn + TimeElapsedColumn) when multiple --source flags given;
single-source path keeps the spinner
- ingest: spinner added (was missing entirely); shows filename and recursive flag
semantica changelog
- Hits GitHub releases API via stdlib urllib; compares latest tag against
__version__; renders release notes in a rounded Panel; --json supported
semantica doctor
- Checks: Python version, semantica/rich versions, graph store reachability,
vector store importability, LLM provider env vars, config file, log dir
- Rich table with ✓/⚠/✗ per check; summary error/warning count at bottom
semantica init
- Interactive wizard: graph backend, vector backend, optional LLM key
- Writes ~/.semantica/config.yaml via yaml.dump; --force to overwrite
semantica watch
- Wraps watchdog Observer; matches configurable glob patterns; auto-ingests
on created/modified events; graceful Ctrl+C shutdown
- Guards ImportError with pip install semantica[watch] hint
_HELP_SECTIONS updated to surface init, doctor, changelog, watch
- description: rewritten to lead with the accountability/provenance
angle and name concrete capabilities; drops emoji which render
inconsistently across PyPI clients
- keywords: expanded from 8 to 23 terms covering modern search queries
(ai-agents, llm, graph-rag, decision-intelligence, provenance, etc.)
- classifiers: added Information Analysis, Text Processing::Linguistic,
Database Engines/Servers, Information Technology audience
- [project.urls]: new section with Homepage, Documentation, Repository,
Changelog, Bug Tracker, Discord — shown prominently on the PyPI page
and drive clicks to GitHub/docs
- optional-dependencies: added watch = [watchdog>=3.0.0]; bundled into all
Prevents UnicodeEncodeError on the default cp1252 code page when Rich
renders box-drawing characters and emoji in the startup banner and panels.
Placed before all other imports so Click and Rich capture the already-
reconfigured streams. Uses reconfigure() (Python 3.7+) which modifies the
existing TextIOWrapper in-place rather than replacing sys.stdout.
- _BANNER: ASCII art shown when `semantica` is run with no subcommand
- _show_startup: dashboard panel with Graph Store / Vector Store / Profile
status cards; suppressed under --quiet and --json
- RichGroup: click.Group subclass that renders --help with grouped sections
(Data Ingestion, Intelligence, Knowledge Graph, Analytics, Export & Viz,
Infrastructure, Services, Tools) plus a Quick Start block
- main decorator: cls=RichGroup + invoke_without_command=True to wire both
- `semantica shell`: interactive REPL that dispatches subcommands while
sharing the parent CLIContext; supports readline on Unix for line editing
- Guard parse_cmd spinner with `fmt == "json"` (default format) to prevent
Rich status output from polluting machine-readable stdout in piped usage
- Remove unused `Rule` import from cli.py
- Remove unused `_orig_print` variable in verify_rich_cli.py
- Unify semantica.cli import style in verify_rich_cli.py; use cli_mod.main
The docs validation workflow runs python docs_check.py with no pip
install step, so rich is not available. Wrap the rich import in a
try/except ModuleNotFoundError and fall back to plain print() calls
so the script works in both environments:
- With rich installed: coloured pass/FAIL output
- Without rich (CI): plain text pass/FAIL output, same exit codes
## Summary
Overhaul the CLI and all library modules to produce polished, modern
terminal output comparable to tools like uv, gh, and cargo. Rich was
already a declared dependency but barely used — this commit wires it
throughout every layer.
## Changes by layer
### semantica/cli.py — visual overhaul
- Add imports: `box`, `Panel`, `Rule`, `Syntax`, `Text` from Rich
- Add 7 style constants (`_BRAND`, `_KEY`, `_VAL`, `_DIM`, `_SUCCESS`,
`_WARN_STY`, `_TABLE_BOX`) for a consistent colour palette
- `_ok()` now prefixes output with a green ✓ checkmark
- New `_info()` helper (neutral · bullet, respects --quiet)
- New `_warn()` helper (yellow ⚠ prefix, never suppressed)
- New `_pprint()` helper: renders dicts/lists as syntax-highlighted JSON
(Rich Syntax, monokai theme) instead of raw Python repr; strings
pass through unchanged; respects --quiet
- `info` command: banner replaced with a rounded Rich Panel showing
version + tagline; component table uses SIMPLE_HEAD box
- All 7 table sites updated: `box=SIMPLE_HEAD`, `show_edge=False`,
consistent `_KEY`/`_VAL` column styles (KG Stats, Reasoning Engines,
Recent Decisions, Configured Backends, Backup Info, MCP Tools)
- `_run_build()`: `console.status(spinner="dots")` wraps the blocking
build call; skipped under --quiet / --json
- `parse`, `extract`, `embed generate`, `reason run`, `reason explain`,
`deduplicate`: each wraps its long-running operation in a status
spinner, guarded by --quiet / --json
- All 30+ `console.print(result)` calls replaced with `_pprint()`
- All raw `[yellow]Warning:[/yellow]` and "not running" patterns
replaced with the new `_warn()` / `_WARN_STY` style
### semantica/explorer/__init__.py
- Error messages use `Console(stderr=True)` with `[bold red]Error:[/bold red]`
- Graph loading wrapped in `console.status()` spinner
- Startup info replaced with a cyan-bordered Rich Panel showing URL,
API docs, and health endpoint
### Library internals — replace print() with structured logger calls
All modules below had active `print()` calls that bypassed the logging
framework, corrupted spinners, and polluted stdout in piped/programmatic
use. All replaced with appropriate `self.logger.*` calls:
- `semantica/kg/graph_builder.py` — 23 calls: entity resolution
progress, graph structure steps, GraphStore persistence timing, and
the two `='*60` completion banners → `self.logger.info/debug()`
- `semantica/semantic_extract/methods.py` — 4 verbose-mode debug
prints → `logger.debug()`
- `semantica/semantic_extract/relation_extractor.py` — progress +
error prints → `self.logger.debug/warning()` with `exc_info`
- `semantica/semantic_extract/triplet_extractor.py` — same pattern
- `semantica/semantic_extract/semantic_network_extractor.py` — batch
error prints → `self.logger.warning/error()`
- `semantica/semantic_extract/coreference_resolver.py` — error print
→ `self.logger.error()`
- `semantica/semantic_extract/providers.py` — debug print →
`self.logger.debug()`
### Tooling
- `benchmarks/benchmarks_runner.py`: Rule banner, ✓/✗/⚠ status lines,
Rule separators around regression alert
- `benchmarks/infrastructure/compare.py`: removed manual ANSI escape
codes; comparison output is now a Rich Table with SIMPLE_HEAD;
summary uses coloured Rule + styled SUCCESS/FAILURE messages
- `cookbook/advanced/snowflake_ingestion_examples.py`: `_section()`
helper using Rule; tabular data rendered as Rich Table; result lines
use ✓/✗/⚠ prefixes; logger.error already present, retained
- `docs_check.py`: `pass`/`FAIL` lines use `[bold green]` /
`[bold red]`; summary uses styled output
## Tests
- `tests/test_cli_commands.py`: fix 3 pre-existing mock mismatches
- `test_kg_stats_json_with_mock`: mock now uses `compute_metrics()`
(the method the code actually calls) instead of `get_statistics()`
- `test_dry_run_not_needed_extract_is_read_only` and
`test_stdin_input`: mock now provides `NERExtractor`,
`RelationExtractor`, `TripletExtractor`, `EventDetector`
(the classes the code imports) instead of `SemanticAnalyzer`
Result: 230/230 tests pass (was 227/230)
- `tests/verify_rich_cli.py`: new verification script; exercises all
14 command groups (92 --help checks, table rendering, dry-run
formatting, --json mode, _pprint helper); 111 pass, 0 fail
- Wire --confidence, --model, --temporal flags to extractors via a flat
extractor_config dict (min_confidence, llm_model, include_temporal)
instead of the unused kwargs dict and sectioned to_dict() spread
- Pass confidence_threshold=confidence directly to RelationExtractor
which exposes it as a named parameter alongside **config
- Remove dead SemanticAnalyzer import and unreachable else branch from
extract; unsupported modes now consistently raise ClickException
- Add _serialize_extract_result() to convert dataclass/list results to
plain dicts so JSON and YAML output is machine-readable, not str()
- Fix kg_stats: remove graph={} arg from compute_metrics() so it uses
the analyzer's loaded graph instead of always computing on empty data
Co-authored-by: Sameer Kadam <sskadam6305@gmail.com>
Co-authored-by: KaifAhmad1 <kaifahmad087@gmail.com>
Covers all 22 command groups introduced in issue #568:
global flags, data in, processing, KG, intelligence (reason/decision/temporal),
provenance, validation, ontology, export, visualize, orchestration
(pipeline/store/backup), services (server/explorer/mcp), and shell completion.
Each section shows real invocation examples rather than flag tables.
P1 — runtime-breaking API mismatches:
- decision record/list/query/trace/similar/impact/check: all six decision
commands now call decision_methods / decision_query using a GraphStore
from _get_graph_store(cli_ctx) instead of passing config= kwargs that
don't exist on the underlying API signatures.
- embed index: load vectors from the Parquet/JSON file into List[np.ndarray]
before calling create_index(), which expects vectors not a file path string.
P2 — stub implementations replaced with real logic:
- backup sync: now collects local data sources via _collect_backup_sources
and performs an incremental copy (skips files whose dst mtime >= src mtime).
- backup restore: detects .enc / tar.gz / .tar / directory, decrypts SEM1
format when --enc, extracts tar archives with leading prefix stripped, or
copies directory trees back to cwd.
P3 — correctness bugs:
- backup create: archive now includes actual config/ontology/store data files
via _collect_backup_sources; manifest records the file list.
- extract: --output now works for all formats (table/rdf/yaml), not only JSON.
- backup create: empty keyfile now raises a clear error instead of silently
producing an unencrypted archive.
- normalize: use Path.is_file() instead of Path.exists() to avoid accidentally
reading a directory that matches the input text.
- visualize: without --output, emit to stdout; do not silently write kg.html.
Minor:
- _setup_cli_logging: replace opaque _ = (quiet, json_output, exc) tuple
with del to suppress unused-variable lint.
- reason list: try to source engines from the reasoning module registry;
fall back to the hardcoded list.
- deduplicate --action report: use method="pairwise" to produce individual
pair objects with similarity scores, distinct from --action detect.
- tests: remove mixed import (from semantica.cli import main) — all 192
runner.invoke calls now use cli_module.main as CodeQL flagged.
- tests: add two focused embed-index regression tests that verify vectors
are loaded from the file before create_index is called.
- embed search: embed query text before calling search_vectors (was passing
raw string to query_vector positional arg, causing TypeError on every call)
- ontology version: import OntologyVersionManager not OntologyVersioning
(symbol never existed; command always failed even with package installed)
- ingest --watch: forward watch flag into _ingest() kwargs (was accepted
but silently dropped, so --watch had no effect)
- store migrate: replace fake success stub with honest ClickException pointing
to the export+embed-index workaround (no bulk-dump API exists in vector store layer)
Fix the export runtime mismatch where get_export_method expected the existing (task, name) registry contract but the CLI passed only the format argument.
Expands semantica/cli.py from a 2-command stub into a complete terminal
interface covering every capability described in issue #568, and ships
253 tests covering all new commands, flags, and error paths.
Co-Authored-By: KaifAhmad1 <kaifahmad087@gmail.com>
- Remove incorrect # pragma: no cover from _run_with_error_handling
generic Exception branch (test_runtime_errors_are_click_safe already
covers it via the monkeypatched RuntimeError path)
- Add _require_ctx() guard: converts None ctx.obj into a clean
ClickException instead of an AttributeError (protects standalone_mode=False
/ library-use callers); apply to info, kg_build, build_alias commands
- Rename serve group -> services to avoid collision with the future
`semantica server` flat command specified in issue #568; update docstring
to document planned subcommand layout
- Fix command-level config logging: re-call setup_logging() with the
command-level config logging section when -c is used (setup_logging
clears handlers before adding, so no accumulation risk)
- Fix missing log_level_override in command_ctx: global --log-level was
silently dropped when a per-command -c config was present, breaking
the override chain for any nested _build_runtime_config calls
- Add return-shape docstring on _run_build documenting the expected
build_knowledge_base() return dict structure
- Add type annotation to runner fixture (-> CliRunner) so Pylance
correctly types runner.invoke() -> Result across all test functions
- Expand test suite: 25 -> 32 tests
* test_info_command_shows_framework_components
* test_info_command_shows_config_path_when_supplied
* test_log_level_global_override_stores_in_context
* test_command_config_preserves_global_log_level_override
* test_build_result_with_stats_shows_source_count
* test_build_result_without_stats_shows_generic_success
* test_build_result_none_shows_generic_success
* test_require_ctx_raises_click_exception_on_none
* test_require_ctx_returns_ctx_unchanged
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- keep command-level config from overriding logging unless --log-level is set
- validate YAML/JSON config roots and surface parse failures as Click errors
- tighten CLI tests around isolation and cleanup
- add CLI runtime context, global config/log-level handling, and click-safe error wrapping
- implement kg build as a thin wrapper over existing orchestrator build flow
- keep hidden legacy build alias and route both build handlers through shared internal path
- add focused CLI tests for help UX, config flag compatibility, alias parity, and clean error output
- keep tests lightweight by mocking heavy build execution paths
- Rename logo PNG to semantica-logo.png (lowercase, hyphenated)
- Update docs.json logo (light/dark) and favicon to reference new PNG
- Replace legacy purple favicon with new teal brain neural network icon