personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add flag syntax to help prompt and improve help CLI UX

Add documented flag syntax (--day, --force, --reprocess, etc.) to
muse/help.md command reference so the help agent stops hallucinating
positional args. Add guardrail instruction. Add more example Q&As.

Add stdin mode to sol help: when invoked with no args, reads a question
from stdin (with interactive prompt on terminals, silent for pipes).

Add "Thinking..." progress indicator to stderr during agent processing,
using streaming Popen instead of blocking subprocess.run.

+74 -29
+27 -12
muse/help.md
··· 15 15 - Use backticks for commands. 16 16 - If the question is unclear, suggest the most likely relevant commands and ask the user to be more specific. 17 17 18 + IMPORTANT: Only suggest commands, subcommands, and flags that are explicitly documented below. Never invent positional arguments, undocumented flags, or syntax not shown here. If you're unsure about a command's syntax, say so rather than guessing. 19 + 18 20 ## Core `sol` Command Reference 19 21 20 22 ### Think (daily processing) 21 - - `sol import` - Import data into the journal. 22 - - `sol dream` - Run daily processing workflows for a day. 23 - - `sol planner` - Run planning workflows. 24 - - `sol indexer` - Build/update the journal index. 23 + - `sol import <media> [--facet NAME] [--source NAME] [--force]` - Import media files into the journal. 24 + - `sol dream [--day YYYYMMDD] [--force] [--segment HHMMSS_LEN] [--facet NAME] [-j N]` - Run daily processing workflows (defaults to yesterday). 25 + - `sol planner -q "question"` - Run planning workflows. Also accepts a task file or `-` for stdin. 26 + - `sol indexer [--day YYYYMMDD] [--rescan] [--rescan-full] [-q QUERY] [--facet NAME]` - Build/update the journal index or search it. 25 27 - `sol supervisor` - Run supervisor services. 26 28 - `sol detect-created` - Detect newly created content artifacts. 27 29 - `sol top` - Show runtime/service activity status. ··· 33 35 - `sol formatter` - Run formatter utilities. 34 36 35 37 ### Observe (capture) 36 - - `sol transcribe` - Transcribe captured audio. 37 - - `sol describe` - Describe visual captures. 38 - - `sol sense` - Run multimodal sensing pipeline. 39 - - `sol sync` - Sync capture artifacts. 40 - - `sol transfer` - Transfer capture data. 38 + - `sol transcribe <audio_path> [--redo] [--backend {whisper,revai,gemini}]` - Transcribe captured audio. 39 + - `sol describe <video_path> [--redo] [-j N]` - Describe visual captures. 40 + - `sol sense [--day YYYYMMDD] [--reprocess {screen,audio,all}] [--segment HHMMSS_LEN] [-j N]` - Run multimodal sensing pipeline. Use `--day` for batch mode. 41 + - `sol sync --remote URL [--days-back N]` - Sync capture artifacts from remote. 42 + - `sol transfer export --day YYYYMMDD [-o PATH]` / `sol transfer import -a ARCHIVE [--dry-run]` - Transfer capture data. 41 43 - `sol observer` - Run observer capture process. 42 44 - `sol observe-linux` - Linux observer entry point. 43 45 - `sol observe-macos` - macOS observer entry point. ··· 49 51 - `sol call` - Run app/built-in call subcommands. 50 52 51 53 ### Convey (web UI) 52 - - `sol convey` - Run Convey web application services. 54 + - `sol convey --port PORT [--skip-maint]` - Run Convey web application services. 53 55 - `sol restart-convey` - Restart Convey service. 54 - - `sol screenshot` - Capture Convey screenshots for routes. 55 - - `sol maint` - Run Convey maintenance commands. 56 + - `sol screenshot <route> [-o FILE] [--facet NAME] [--width N] [--height N]` - Capture Convey screenshots for routes. 57 + - `sol maint [task] [-l] [-f]` - Run Convey maintenance commands. Use `-l` to list available tasks. 56 58 57 59 ### Help and aliases 58 60 - `sol help "question"` - Ask this help assistant how to use commands. 61 + - `sol help` - Enter interactive mode (type question, Ctrl+D to submit). 59 62 - `sol start` - Alias for `sol supervisor`. 60 63 61 64 ## `sol muse` Commands ··· 106 109 - If asked "How do I inspect an agent run?": 107 110 - Use `sol muse logs` to find run IDs. 108 111 - Use `sol muse log <id>` for event details. 112 + - If asked "How do I reprocess audio for a specific day?": 113 + - Use `sol sense --day YYYYMMDD --reprocess audio` to reprocess audio for that day. 114 + - Use `--reprocess all` to reprocess both audio and screen. 115 + - If asked "How do I run daily processing for yesterday?": 116 + - Use `sol dream` — it defaults to yesterday. 117 + - Use `sol dream --day YYYYMMDD` for a specific day. 118 + - Add `--force` to reprocess even if already done. 119 + - If asked "How do I search for something in my journal?": 120 + - Use `sol call journal search "query"` for full-text search. 121 + - Add `-d YYYYMMDD` or `--day-from`/`--day-to` for date ranges. 122 + - Add `-f facet` to filter by project/context. 123 + - Use `sol indexer -q "query"` for a quick index search.
+47 -17
think/help_cli.py
··· 13 13 from think.utils import setup_cli 14 14 15 15 16 + def _read_stdin() -> str: 17 + """Read a question from stdin. Shows a prompt if running in a terminal.""" 18 + if sys.stdin.isatty(): 19 + print( 20 + "Enter your question (Ctrl+D to submit):", 21 + file=sys.stderr, 22 + ) 23 + try: 24 + return sys.stdin.read().strip() 25 + except KeyboardInterrupt: 26 + return "" 27 + 28 + 16 29 def main() -> None: 17 30 """Entry point for ``sol help``.""" 18 31 parser = argparse.ArgumentParser( ··· 28 41 args = setup_cli(parser) 29 42 30 43 if not args.question: 31 - # Imported here to avoid circular import (sol.py imports think.help_cli). 32 - from sol import print_help 44 + question = _read_stdin() 45 + if not question: 46 + # Imported here to avoid circular import (sol.py imports think.help_cli). 47 + from sol import print_help 33 48 34 - print_help() 35 - return 49 + print_help() 50 + return 51 + else: 52 + question = " ".join(args.question).strip() 36 53 37 - question = " ".join(args.question).strip() 38 54 config = {"name": "help", "prompt": question} 39 55 config_json = json.dumps(config) 56 + 57 + print("Thinking...", end="", file=sys.stderr, flush=True) 40 58 41 59 try: 42 - result = subprocess.run( 60 + proc = subprocess.Popen( 43 61 ["sol", "agents"], 44 - input=config_json + "\n", 45 - capture_output=True, 62 + stdin=subprocess.PIPE, 63 + stdout=subprocess.PIPE, 64 + stderr=subprocess.PIPE, 46 65 text=True, 47 - timeout=120, 48 66 ) 49 - except subprocess.TimeoutExpired: 50 - print("Error: help request timed out after 120 seconds.", file=sys.stderr) 51 - sys.exit(1) 52 67 except Exception as exc: 53 - print(f"Error: failed to run help agent: {exc}", file=sys.stderr) 68 + print(f"\rError: failed to run help agent: {exc}", file=sys.stderr) 54 69 sys.exit(1) 55 70 71 + assert proc.stdin is not None # for type checker 72 + proc.stdin.write(config_json + "\n") 73 + proc.stdin.close() 74 + 56 75 finish_result: str | None = None 57 76 errors: list[str] = [] 58 77 59 - for line in result.stdout.splitlines(): 78 + assert proc.stdout is not None # for type checker 79 + for line in proc.stdout: 60 80 line = line.strip() 61 81 if not line: 62 82 continue ··· 70 90 if event_type == "error": 71 91 errors.append(str(event.get("error", "Unknown error"))) 72 92 elif event_type == "finish": 73 - # Keep the last finish result seen in the stream. 74 93 result_value = event.get("result") 75 94 finish_result = "" if result_value is None else str(result_value) 76 95 96 + try: 97 + proc.wait(timeout=120) 98 + except subprocess.TimeoutExpired: 99 + proc.kill() 100 + print("\rError: help request timed out after 120 seconds.", file=sys.stderr) 101 + sys.exit(1) 102 + 103 + # Clear the "Thinking..." indicator. 104 + print("\r \r", end="", file=sys.stderr, flush=True) 105 + 77 106 for message in errors: 78 107 print(f"Error: {message}", file=sys.stderr) 79 108 ··· 85 114 print("Error: help agent returned an empty result.", file=sys.stderr) 86 115 sys.exit(1) 87 116 88 - if result.returncode != 0 and result.stderr.strip(): 89 - print(f"Error: {result.stderr.strip()}", file=sys.stderr) 117 + stderr_output = proc.stderr.read() if proc.stderr else "" 118 + if proc.returncode != 0 and stderr_output.strip(): 119 + print(f"Error: {stderr_output.strip()}", file=sys.stderr) 90 120 else: 91 121 print("Error: no help response received.", file=sys.stderr) 92 122 sys.exit(1)