An open API service indexing awesome lists of open source software.

https://github.com/smart-ai-memory/attune-help

Lightweight .help/ runtime reader with progressive depth. Python package for the attune-docs help platform.
https://github.com/smart-ai-memory/attune-help

Last synced: about 2 months ago
JSON representation

Lightweight .help/ runtime reader with progressive depth. Python package for the attune-docs help platform.

Awesome Lists containing this project

README

          

# attune-help

Lightweight help runtime with progressive depth and
audience adaptation. Read project help templates
generated by [attune-ai](https://pypi.org/project/attune-ai/).

## Install

```bash
pip install attune-help
```

## Quick Start

```python
from attune_help import HelpEngine

engine = HelpEngine(template_dir=".help/templates")

# Progressive depth: concept -> task -> reference
print(engine.lookup("security-audit")) # concept
print(engine.lookup("security-audit")) # task
print(engine.lookup("security-audit")) # reference
```

## How It Works

Each topic has three depth levels:

| Level | Type | What you get |
|-------|------|-------------|
| 0 | Concept | What is it? When to use it? |
| 1 | Task | Step-by-step how-to |
| 2 | Reference | Full detail, edge cases |

Repeated lookups on the same topic auto-advance.
A new topic resets to concept.

## Renderers

```python
# Plain text (default)
engine = HelpEngine(renderer="plain")

# Rich terminal output (requires `pip install attune-help[rich]`)
engine = HelpEngine(renderer="cli")

# Claude Code inline format
engine = HelpEngine(renderer="claude_code")

# Structured JSON (for apps, web, tests)
engine = HelpEngine(renderer="json")

# Auto-detect environment (CLAUDE_CODE → claude_code,
# interactive TTY + rich → cli, otherwise → plain)
engine = HelpEngine(renderer="auto")

# Switch renderer at runtime
engine.set_renderer("cli")
```

Passing an unknown renderer name raises `ValueError`.

## Template Directory

Templates are markdown files with YAML frontmatter:

```
.help/templates/
security/
concept.md
task.md
reference.md
api/
concept.md
task.md
reference.md
```

Generate templates with
[attune-ai](https://pypi.org/project/attune-ai/):

```bash
pip install attune-ai
# Then in Claude Code:
/coach init
```

Or create them manually — any markdown file with
`feature`, `depth`, and `source_hash` frontmatter
fields works.

## Demo Templates

The package includes a demo feature showing the
progressive depth format:

```python
from attune_help import get_demo_path

# Copy to your project
import shutil
shutil.copytree(
get_demo_path() / "security-audit",
".help/templates/security-audit",
)
```

The `security-audit/` demo contains `concept.md`,
`task.md`, and `reference.md` — the three depth
levels that `/coach init` generates for each feature.

## Discovery

```python
engine.list_topics() # all slugs
engine.list_topics(type_filter="concepts") # filter by type
engine.search("security") # [(slug, score), ...]
engine.suggest("secrity-audit") # ranked slugs
```

Miss handling:

```python
# Returns None by default
engine.lookup("typoed-slug")

# Returns "No help for 'typoed-slug'. Did you mean: ..."
engine.lookup("typoed-slug", suggest_on_miss=True)
```

## Progressive Depth Controls

```python
engine.lookup("security-audit") # concept
engine.lookup("security-audit") # task
engine.lookup("security-audit") # reference (depth 2)

engine.simpler("security-audit") # step back to task
engine.simpler("security-audit") # step back to concept

engine.reset("security-audit") # clear one topic
engine.reset() # clear all topics
```

Topics are tracked independently — interleaving
`lookup("a")` / `lookup("b")` / `lookup("a")` does **not**
reset `a`'s depth. An LRU cap of 32 topics keeps session
state bounded.

## MCP Server

Install with the plugin extra and use as an MCP server:

```bash
pip install attune-help[plugin]
attune-help-mcp # stdio transport
```

Exposed tools (all prefixed `lookup_` for namespace
hygiene against other plugins):

| Tool | Purpose |
|------|---------|
| `lookup_topic` | Progressive depth lookup |
| `lookup_simpler` | Step a topic one level back |
| `lookup_reset` | Clear a single topic or full session |
| `lookup_status` | Read session state (topics + LRU order) |
| `lookup_list` | Category-grouped topic enumeration |
| `lookup_list_topics` | Flat slug enumeration (optionally by type) |
| `lookup_search` | Fuzzy slug search with scores |
| `lookup_suggest` | "Did you mean" slug suggestions |
| `lookup_warn` | File-context warnings for a path |
| `lookup_preamble` | "Use X when..." one-liner for a feature |

All tools that render help content accept the same
renderer set as the Python API: `plain`, `claude_code`,
`cli`, `marketplace`, `json` (the `auto` sentinel is
excluded because auto-detection is meaningless over a
protocol boundary).

## API

### `HelpEngine`

```python
HelpEngine(
template_dir=None, # Override template path
storage=None, # Session storage backend
renderer="plain", # Output renderer
user_id="default", # Session tracking ID
)
```

**Methods:**

- `lookup(topic, *, suggest_on_miss=False)` — Progressive
depth lookup with optional "did you mean" on miss
- `simpler(topic)` — Step back one depth level
- `reset(topic=None)` — Clear depth history for one topic
or all
- `list_topics(type=None, limit=None)` — Enumerate slugs
- `search(query, limit=10)` — Fuzzy-search slugs
- `suggest(topic, limit=5)` — Ranked slug suggestions
- `get(template_id)` — Direct template access
- `lookup_raw(topic)` — Returns `PopulatedTemplate`
dataclass
- `get_summary(skill)` — One-line skill summary (falls
back to bundled when an override lacks it)
- `precursor_warnings(file_path)` — File-aware warnings
(supports Python, JS/TS, Rust, Go, Ruby, Java, …)
- `set_renderer(name)` — Change renderer at runtime

### `SessionStorage` Protocol

Implement custom storage backends:

```python
from attune_help import SessionStorage

class RedisStorage(SessionStorage):
def load(self, user_id: str) -> dict: ...
def save(self, user_id: str, state: dict) -> None: ...
```

## Staleness Detection

`attune-help` tracks whether your help templates are up to date with
your source code using SHA-256 hashes stored in template frontmatter.

### Basic usage

```python
from attune_help import load_manifest, check_staleness

manifest = load_manifest(".help")
report = check_staleness(manifest, help_dir=".help", project_root=".")

for entry in report.stale_features:
print(f"{entry} is stale — regenerate with attune-ai")
```

### Semantic hashing (v0.10+)

For pure-Python features, `compute_source_hash` automatically uses
**semantic hashing**: only public-symbol *contracts* (parameters, return
types, decorators, base classes) contribute to the hash. Docstring
edits, body rewrites, and formatter passes (`black`, `ruff`) are
ignored. This eliminates spurious template regenerations when nothing
meaningful changed.

```python
from attune_help import compute_source_hash, compute_semantic_hash
from attune_help.manifest import Feature

feat = Feature(name="auth", description="", files=["src/auth/**"])

# compute_source_hash uses semantic hashing automatically for .py-only features
hash1, files = compute_source_hash(feat, project_root=".")

# Call compute_semantic_hash directly when you need the semantic hash
# regardless of file mix (e.g. for reporting)
hash2, files = compute_semantic_hash(feat, project_root=".")
```

Mixed-content features (Python + Jinja, YAML, etc.) and features with
syntax errors in their source files fall back to byte-level SHA
automatically — no configuration required.

### Corpus validation

A 3-sweep validation harness ships in `scripts/validate_against_corpus.py`:

```bash
# Validate against any repo with a .help/features.yaml
python scripts/validate_against_corpus.py --repo /path/to/your/repo
```

Sweeps: (1) parse integrity — all `.py` files parse cleanly; (2)
determinism — identical hashes on two consecutive calls; (3) HEAD vs
HEAD^ — classifies symbol changes as signature drift / body-only /
add / remove.

## Template aliases

Templates can declare `aliases:` in their frontmatter to cover
retrieval gaps — synonyms and alternate phrasings that keyword search
would otherwise miss:

```yaml
---
type: concept
feature: tool-planning
aliases:
- how to plan tools
- tool design principles
- when to use tools
---
```

`aliases` is a YAML list of strings. The retrieval engine scores alias
hits the same as title hits, so a query that uses a synonym routes to
the right template even when the canonical slug has no token overlap.

## License

Apache 2.0