Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

MetaMuse CLI

Turn comments and transcripts into a recap you can check against the originals.

Have event feedback to review, or a video transcript to quote? MetaMuse keeps your permitted source material, finds matching passages, and saves drafts with their citations. You or your AI assistant writes the recap; MetaMuse keeps the originals and the export together on your computer.

Use it from a terminal, or connect it to an AI assistant that can run CLI or MCP tools. The tool runs on your machine.

Try the example · 繁體中文上手指南 · Connect accounts and publish · Connect your assistant

What can I do with it?

  • Review event feedback: find comments about a request, then have your assistant draft a recap with links to the original comments.
  • Find a passage in a transcript: import local SRT or VTT subtitles and search for words you want to quote.
  • Keep a checkable draft: save your text with source references and export Markdown, text, CSV, JSONL or a bundle.

Search currently matches literal text. Your assistant handles interpretation and writing; a saved citation still needs your review.

Try it

Install uv, then install the alpha package and run the bundled example. These instructions target 0.1.0a2; PyPI lists the available releases. uv manages the Python version and creates an isolated environment for the command.

uv tool install --python 3.12.13 'metamuse-cli==0.1.0a2'
metamuse demo

Installation downloads Python and dependencies. The example itself runs locally with synthetic comments and a prewritten recap. It needs no account, Muse connection or AI service.

You will import three records, search for 字幕 (subtitles), and export a Markdown recap with the matching comment and its source reference. The terminal prints Export directory:; open the .md files there to see the result. This is a demonstration of the data workflow, not an AI-generated analysis.

Every run creates a separate workspace outside the checkout, under your system's user data directory (metamuse/demos/). It stays there so you can inspect it. Delete the workspace printed by the example when you no longer need it.

The getting started guide (繁體中文) shows the expected result and how to move on to your own files. The sample inputs are in src/metamuse/data/examples/event-comments.jsonl.

Use it with your AI assistant

Connect the installed CLI using the Skill setup guide, or configure the MCP server. Loading the Skill supplies instructions; your assistant also needs access to the working CLI or MCP backend.

Once connected, try a request like this:

Use MetaMuse to review the event comments I provide and have permission to use. Find feedback about subtitles, group the requests, and draft a recap with links to the original comments. Show me the sources and gaps before saving. Export Markdown and keep this work local.

Muse is an optional collaborator for further questions. Local import, search, drafts and exports work without a Muse account. A real Muse connection needs separate configuration and human approval. Version 0.1.0a2 includes the compatibility fixes tested with two real Muse turns using synthetic input, restart/read-back and cited draft exports. That test crossed candidate builds; it was not a fresh end-to-end test of one unchanged release. The Muse guide records the scope. Version 0.1.0a1 lacks these fixes.

Use metamuse connect muse, connect facebook, or connect publishing to validate your private credential file and bind the account without editing TOML. Add --enable-network to explicitly enable network use; each external action still needs its own approval. The connected workflow guide (中文) walks through setup, collecting one post, Muse follow-ups, a cited draft and Page publication. This complete sequence has synthetic integration coverage; real-account acceptance is pending.

What can I use today?

Start with files on your computer. You can search, save drafts and export without a Muse account. Your assistant handles interpretation and writing once connected.

What you want to do Availability What you get
Import saved comments and subtitles Ready with local files Bring together the saved comments, articles and subtitle files you already have, so you can find them later.
Find a comment or transcript passage Ready with local files Search for a word such as subtitles, then read the matching text and its source.
Keep a draft with its sources Ready with local files Save text you or your assistant wrote, together with the original material you cited.
Export a file you can edit Ready with local files Keep your draft and material as text documents or spreadsheet-friendly files for further editing.
Work with your AI assistant Connect your assistant first Connect your assistant to MetaMuse, then ask it to find material and draft a recap with citations.
Ask Muse follow-up questions Requires 0.1.0a2 and account setup Select material to share, ask Muse a question, then follow up in the same conversation. A bounded synthetic-input test with a real account succeeded across corrected candidate builds; 0.1.0a2 includes those fixes.
Collect a Facebook post or remote video Needs extra setup; real-account use is unverified Additional setup and your approval are required. These collectors have not been verified with real accounts.
Publish a text post to a Facebook Page Requires 0.1.0a2 and account setup Approve the exact text and Page, then send and check the receipt. One real test post and read-only reconciliation succeeded across corrected candidate builds; 0.1.0a2 includes the read-back fix. Text-only and experimental; setup and limits.

See the getting started guide to try the local example, or connect your assistant to use your own material. Developers can find the implementation and verification inventory in the development documentation.

Advanced: ask Muse follow-up questions with one bounded approval

The implemented bounded research workflow lets a human approve a fixed packet, topic, expiry and question/read budget. Your assistant can then ask varied questions within that scope, keep the discussion across restarts, and save a draft citing sources and Muse observations. Changed data or scope needs new consent. The guide distinguishes fixture coverage from the bounded real-account test and documents the fixes included in 0.1.0a2.

Advanced: full command-by-command offline example, including fixture Muse

Local offline walkthrough

Run from the repository root after uv sync --python 3.12. This synthetic walkthrough collects data, previews a packet, opens a fixture Muse discussion, asks a question and a follow-up in the same discussion, saves host-written text and exports five formats. The host shows the human each E_SCOPE_REQUIRED approval preview. Only the human runs operator permit approve, reviews its stderr (including expiry and uses), and repeats the unchanged call with the returned grant. The agent never approves. Evidence is OFFLINE/FIXTURE, with no network or accounts.

These Bash blocks run in order. Python only edits configuration and copies public JSON fields; every product operation uses the shipped CLI. tests/test_readme_walkthrough.py executes these exact blocks in a temporary workspace.

export UV_OFFLINE=1
mkdir -p "$HOME/agent-work/tmp"
export SLICE_DIR="${SLICE_DIR:-$(mktemp -d "$HOME/agent-work/tmp/metamuse-at042-XXXXXX")}"
export SLICE_WS="$SLICE_DIR/workspace"
mkdir "$SLICE_DIR/inputs"
mm() { uv run metamuse --workspace "$SLICE_WS" --json --non-interactive "$@"; }
operator() { uv run metamuse --workspace "$SLICE_WS" --json "$@"; }
field() { uv run python -c 'import json,sys; print(json.load(open(sys.argv[1]))["data"][sys.argv[2]])' "$1" "$2"; }
approval_field() { uv run python -c 'import json,sys; print(json.load(open(sys.argv[1]))["approval"][sys.argv[2]])' "$1" "$2"; }
preview() {
  local output="$1"; shift
  local result=0
  mm "$@" > "$output" || result=$?
  test "$result" -eq 3
  uv run python -c 'import json,sys; e=json.load(open(sys.argv[1])); assert e["error"]["code"] == "E_SCOPE_REQUIRED" and e["approval"]; print(e["approval"]["summary"]); print(e["approval"]["next_action"])' "$output"
}
save_request() {
  uv run python -c 'import json,sys; a=json.load(open(sys.argv[1]))["approval"]; json.dump(a["request"],open(a["request_file"],"w"),ensure_ascii=False)' "$1"
}

mm init > "$SLICE_DIR/init.json"
uv run python - <<'PYTHON'
import json, os
from pathlib import Path
root = Path(os.environ['SLICE_DIR'])
config = Path(os.environ['SLICE_WS']) / 'metamuse.toml'
text = config.read_text().replace('[app]\n', '[app]\nimport_roots = ' + json.dumps([str(root / 'inputs')]) + '\n')
text = text.replace('[muse]\nenabled = false', '[muse]\nenabled = true\nbackend = "fixture"')
config.write_text(text)
corpus = Path('tests/fixtures/corpus/import/comments_tree.jsonl')
(root / 'inputs/comments.jsonl').write_text('\n'.join(corpus.read_text().splitlines()[:3]) + '\n')
PYTHON
mm doctor > "$SLICE_DIR/doctor.json"
mm project create --name 'Synthetic slice' --request-key project > "$SLICE_DIR/project.json"
export SLICE_PROJECT=$(field "$SLICE_DIR/project.json" id)
mm add --project "$SLICE_PROJECT" --file "$SLICE_DIR/inputs/comments.jsonl" --kind jsonl --request-key import --run > "$SLICE_DIR/import.json"
mm search --project "$SLICE_PROJECT" --query '這是' > "$SLICE_DIR/search.json"
uv run python - <<'PYTHON'
import json, os
from pathlib import Path
root = Path(os.environ['SLICE_DIR'])
hits = json.loads((root / 'search.json').read_text())['data']['results']
(root / 'inputs/selection.json').write_text(json.dumps([hit['ref'] for hit in hits]))
PYTHON
mm packet prepare --project "$SLICE_PROJECT" --selection-file "$SLICE_DIR/inputs/selection.json" --request-key packet > "$SLICE_DIR/packet.json"
export SLICE_PACKET=$(field "$SLICE_DIR/packet.json" id)
mm packet preview "$SLICE_PACKET" > "$SLICE_DIR/packet-preview.json"
cat "$SLICE_DIR/packet-preview.json"

Call without a grant, show the review and its human command, save the public request, then approve the exact digest. Credential-like values are redacted separately in every text field. A redacted or edited request fails the original digest; it must be reviewed again. Expired, revoked, exhausted or mismatched grants return E_SCOPE_DENIED without a preview. Repeat without a grant to get a fresh review.

preview "$SLICE_DIR/open-preview.json" muse open --project "$SLICE_PROJECT" --topic 'Synthetic activity review' --request-key open
save_request "$SLICE_DIR/open-preview.json"
operator permit approve --operation muse.open --request-file "$(approval_field "$SLICE_DIR/open-preview.json" request_file)" --exact-digest "$(approval_field "$SLICE_DIR/open-preview.json" action_digest)" --request-key open-grant > "$SLICE_DIR/open-grant.json"
mm muse open --project "$SLICE_PROJECT" --topic 'Synthetic activity review' --access-grant "$(field "$SLICE_DIR/open-grant.json" id)" --request-key open > "$SLICE_DIR/open.json"
export SLICE_DISCUSSION=$(field "$SLICE_DIR/open.json" discussion_id)
mm jobs get "$(field "$SLICE_DIR/open.json" job_id)"
mm worker run --once
mm jobs get "$(field "$SLICE_DIR/open.json" job_id)"

printf '%s' 'List evidence and gaps.' > "$SLICE_DIR/inputs/question-1.txt"
printf '%s' 'Which missing replies would change those conclusions?' > "$SLICE_DIR/inputs/question-2.txt"
for exchange in 1 2; do
  preview "$SLICE_DIR/send-preview-$exchange.json" muse send --discussion "$SLICE_DISCUSSION" --packet "$SLICE_PACKET" --question-file "$SLICE_DIR/inputs/question-$exchange.txt" --request-key "send-$exchange"
  mm packet preview "$SLICE_PACKET"
  save_request "$SLICE_DIR/send-preview-$exchange.json"
  operator permit approve --operation muse.send --request-file "$(approval_field "$SLICE_DIR/send-preview-$exchange.json" request_file)" --exact-digest "$(approval_field "$SLICE_DIR/send-preview-$exchange.json" action_digest)" --request-key "share-grant-$exchange" > "$SLICE_DIR/share-grant-$exchange.json"
  mm muse send --discussion "$SLICE_DISCUSSION" --packet "$SLICE_PACKET" --question-file "$SLICE_DIR/inputs/question-$exchange.txt" --share-grant "$(field "$SLICE_DIR/share-grant-$exchange.json" id)" --request-key "send-$exchange" > "$SLICE_DIR/send-$exchange.json"
  export SLICE_EXCHANGE=$(field "$SLICE_DIR/send-$exchange.json" exchange_id)
  mm jobs get "$(field "$SLICE_DIR/send-$exchange.json" job_id)"
  mm worker run --once
  mm jobs get "$(field "$SLICE_DIR/send-$exchange.json" job_id)"
  preview "$SLICE_DIR/read-preview-$exchange.json" muse read --exchange "$SLICE_EXCHANGE" --refresh
  save_request "$SLICE_DIR/read-preview-$exchange.json"
  operator permit approve --operation muse.read --request-file "$(approval_field "$SLICE_DIR/read-preview-$exchange.json" request_file)" --exact-digest "$(approval_field "$SLICE_DIR/read-preview-$exchange.json" action_digest)" --request-key "read-grant-$exchange" > "$SLICE_DIR/read-grant-$exchange.json"
  mm muse read --exchange "$SLICE_EXCHANGE" --refresh --access-grant "$(field "$SLICE_DIR/read-grant-$exchange.json" id)" > "$SLICE_DIR/refresh-$exchange.json"
  mm worker run --once
  mm muse read --exchange "$SLICE_EXCHANGE" > "$SLICE_DIR/read-$exchange.json"
  mm muse close-exchange "$SLICE_EXCHANGE" --outcome needs_more_data --request-key "close-$exchange" > "$SLICE_DIR/close-$exchange.json"
done

The fixture replies are progress, so the operator closes each exchange as needs_more_data. Draft text comes from the host and cites observations from both exchanges. CLI invocations have already restarted the application between steps; the separate MCP acceptance test also restarts a real stdio server and checks that no send repeats.

uv run python - <<'PYTHON'
import json, os
from pathlib import Path
root = Path(os.environ['SLICE_DIR'])
facts = json.loads((root / 'inputs/selection.json').read_text())
citations = []
for exchange in (1, 2):
    read = json.loads((root / f'read-{exchange}.json').read_text())['data']
    assistant_ids = {message['id'] for message in read['messages'] if message['role'] == 'assistant'}
    observed = next(o for o in read['observations'] if o['message_id'] in assistant_ids and o['raw_event'].get('payload',{}).get('role') == 'assistant')
    assert read['mock'] and read['research_complete'] is False
    facts.append(observed['evidence_ref'])
    citations.append(observed['id'])
(root / 'inputs/facts.json').write_text(json.dumps(facts))
host_text = '=活動回顧(host 撰寫)\r\n首輪列出缺口;追問指出仍需要留言與子回覆。😀 e\u0301\n'
(root / 'inputs/draft.txt').write_bytes((host_text + '\n引用:' + ', '.join(citations) + '\n').encode())
PYTHON
mm draft save --project "$SLICE_PROJECT" --text-file "$SLICE_DIR/inputs/draft.txt" --platform generic --facts-file "$SLICE_DIR/inputs/facts.json" --request-key draft > "$SLICE_DIR/draft.json"
export SLICE_DRAFT=$(field "$SLICE_DIR/draft.json" draft_id)
mm draft preview "$SLICE_DRAFT" --revision 1 > "$SLICE_DIR/preview.json"
uv run python - <<'PYTHON'
import json, os
from pathlib import Path
(Path(os.environ['SLICE_DIR']) / 'inputs/export-refs.json').write_text(json.dumps([{'kind':'draft_revision','id':os.environ['SLICE_DRAFT'],'revision':1}]))
PYTHON
for format in bundle jsonl markdown text csv; do
  mm export --project "$SLICE_PROJECT" --refs-file "$SLICE_DIR/inputs/export-refs.json" --format "$format" --request-key "export-$format" > "$SLICE_DIR/export-$format.json"
done
cat "$SLICE_DIR/preview.json" "$SLICE_DIR/export-bundle.json"
if [ "${SLICE_KEEP:-0}" != 1 ]; then rm -rf -- "$SLICE_DIR"; fi

Skill

The canonical Skill tree is skills/metamuse/. The wheel ships the same files, and metamuse skill export --dest DIR writes them to a directory the operator names. It is not an MCP tool. Installation steps are in SKILL.md. The Skill requires an installed, reachable MetaMuse backend (CLI or MCP server) to execute operations; when the backend is unavailable, operations cannot be simulated.

Development and project details

One package (metamuse) and one shared application serve the CLI, MCP server and Skill. See the design baseline, core API, collection formats, and full offline walkthrough.

For development, use Python 3.12 managed by uv:

pytest-disktmp uv run pytest -q
uv run ruff check .

Runtime workspaces belong outside the checkout. Credentials, account settings, real collected data and LIVE evidence stay outside this repository and are supplied by the operator at runtime.

This is an unofficial project, unaffiliated with Meta, Facebook or Muse. It does not claim official API access, terms-of-service compliance or protection against account restrictions.

License: Apache-2.0. Dependency notices: THIRD_PARTY_NOTICES.md.

Metadata

Release files for metamuse-cli 0.1.0a2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for metamuse-cli 0.1.0a2
File Size Uploaded Provenance Actions
metamuse_cli-0.1.0a2.tar.gz 4.8 MB Without provenance Details for metamuse_cli-0.1.0a2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for metamuse-cli 0.1.0a2
File Interpreter ABI Platform Actions
metamuse_cli-0.1.0a2-py3-none-any.whl Python 3 none any Details for metamuse_cli-0.1.0a2-py3-none-any.whl

Total release size: 5.2 MB

Release files / metamuse_cli-0.1.0a2.tar.gz

Download URL metamuse_cli-0.1.0a2.tar.gz
Size 4.8 MB
Tags Source
SHA-256 checksum
How to use checksums
5de4f27f463a5c207248a7ff25ff76ee6dad9a0639eb46d5c6a3fdf00758dd90
BLAKE2b-256 checksum
How to use checksums
96bf64418c362da127d0e6c3147000ab0d7d2782a3f98a3ec716a69ff523320e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / metamuse_cli-0.1.0a2-py3-none-any.whl

Download URL metamuse_cli-0.1.0a2-py3-none-any.whl
Size 431.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
15ec56c5314db1f3f592eb1aa358ec82dbba27eb7e116aa33dca6549ba3df2d0
BLAKE2b-256 checksum
How to use checksums
c12d43273d0daa759a7e1c1e8fe329627f204494c424e52c97a58b7f416f3fff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for metamuse-cli 0.1.0a2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page