From ab4b217d18d9de634687cd738f77e43edcacdda3 Mon Sep 17 00:00:00 2001
From: OpenClaw
Date: Sun, 19 Jul 2026 21:51:54 -0500
Subject: [PATCH 1/6] =?UTF-8?q?rename:=20synthpanel=20=E2=86=92=20althing?=
=?UTF-8?q?=20across=20the=20codebase?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The project is now Althing (althing.dev). Canonical import module is
althing (one word), retiring the synth_panel/synthpanel split from #509.
- dist/CLI/module: althing; env vars ALTHING_* (SYNTHPANEL_* honored
with a DeprecationWarning via a central bridge in althing/__init__)
- synthpanel + synth_panel kept as deprecation shim modules (__path__
redirect + PEP 562 __getattr__ delegation)
- synthpanel console script kept as deprecated alias
- shim-dist/: transitional PyPI metapackage so pip install synthpanel
keeps working (depends on althing); publish.yml builds both dists
- site: canonical URLs → althing.dev, _redirects for renamed blog slug
and agent-skills path; agent-skills index regenerated
- version 1.6.0 → 1.7.0 (rename release)
- historical CHANGELOG entries retain the old name
Co-Authored-By: Claude Fable 5
---
.claude-plugin/plugin.json | 8 +-
.env.example | 4 +-
.github/ISSUE_TEMPLATE/bug_report.yml | 4 +-
.github/pull_request_template.md | 2 +-
.github/scripts/verify-ci-checks.sh | 2 +-
.github/workflows/auto-tag.yml | 10 +-
.github/workflows/ci.yml | 40 +-
.github/workflows/docker.yml | 10 +-
.github/workflows/publish-test.yml | 20 +-
.github/workflows/publish.yml | 18 +-
.gitignore | 4 +-
CHANGELOG.md | 20 +-
CONTRIBUTING.md | 24 +-
Dockerfile | 34 +-
README.md | 354 +++++------
SECURITY.md | 2 +-
SPEC.md | 30 +-
.../{synthpanel-poll.md => althing-poll.md} | 14 +-
docs/RELEASING.md | 36 +-
docs/adapter-guide.md | 58 +-
docs/agent-discovery-audit.md | 84 +--
docs/agent-integration-landscape.md | 98 +--
docs/agent-quickstart.md | 78 +--
docs/agent-skills.md | 80 +--
docs/ai-engineer-readiness.md | 44 +-
.../dispatch-symmetry-anti-pattern.md | 24 +-
... => althing-vs-commercial-alternatives.md} | 52 +-
docs/brand.md | 16 +-
docs/calibration.md | 18 +-
docs/cloudflare-pages-setup.md | 32 +-
docs/composio-submission.md | 62 +-
docs/convergence.md | 20 +-
...ynthetic_Focus_Group_With_SynthPanel.ipynb | 36 +-
.../cookbook/instrument-regression-testing.md | 24 +-
docs/cookbook/with-attachments.md | 4 +-
docs/distribution-and-pitch.md | 32 +-
docs/ensemble.md | 4 +-
...nal-contributor-safety-audit-2026-04-15.md | 34 +-
docs/mcp.md | 120 ++--
docs/methodology.md | 12 +-
docs/migration-v1.md | 16 +-
docs/model-packs.md | 22 +-
docs/oauth-discovery.md | 16 +-
docs/production-operations.md | 90 +--
docs/recommended-models.md | 48 +-
docs/registry-submissions.md | 48 +-
docs/registry.md | 84 +--
docs/release-audit-2026-04-15.md | 40 +-
docs/release-dogfood-protocol.md | 12 +-
docs/reproducibility.md | 14 +-
docs/response-contract.md | 30 +-
docs/site-audit-2026-04-30.md | 32 +-
docs/stability.md | 16 +-
docs/structured-polling.md | 60 +-
docs/synthbench-integration.md | 28 +-
docs/task-recommendations.md | 40 +-
docs/traitprint-local-signoff.md | 18 +-
docs/vscode-extension-decision.md | 4 +-
examples/README.md | 38 +-
examples/consumer-name-test/README.md | 8 +-
examples/devtools-pricing/README.md | 10 +-
examples/instruments/general_survey.yaml | 4 +-
examples/instruments/market_research.yaml | 4 +-
examples/instruments/product_feedback.yaml | 4 +-
examples/instruments/with-attachments.yaml | 2 +-
examples/integrations/README.md | 68 +--
examples/integrations/composio_crewai.py | 14 +-
examples/integrations/composio_langchain.py | 14 +-
examples/integrations/crewai_tool.py | 16 +-
examples/integrations/langchain_tool.py | 10 +-
examples/integrations/llamaindex_tool.py | 10 +-
examples/integrations/microsoft_agent.py | 16 +-
examples/integrations/n8n_workflow.json | 10 +-
examples/integrations/openai_agents.py | 20 +-
examples/saas-onboarding-friction/README.md | 6 +-
examples/sdk_usage.py | 6 +-
pyproject.toml | 44 +-
scripts/check_site_cli_sync.py | 8 +-
scripts/refresh_or_cost_table.py | 8 +-
scripts/render_agent_skills.py | 4 +-
scripts/render_server_card.py | 10 +-
scripts/render_site.py | 6 +-
scripts/site_tailwind/package-lock.json | 4 +-
scripts/site_tailwind/package.json | 2 +-
scripts/site_tailwind/tailwind.config.js | 2 +-
server.json | 12 +-
shim-dist/README.md | 20 +
shim-dist/pyproject.toml | 30 +
.../agent-skills/althing}/SKILL.md | 90 +--
.../agent-skills/concept-test/SKILL.md | 24 +-
.../agent-skills/focus-group/SKILL.md | 20 +-
site/.well-known/agent-skills/index.json | 18 +-
.../agent-skills/name-test/SKILL.md | 24 +-
.../agent-skills/pricing-probe/SKILL.md | 22 +-
.../agent-skills/survey-prescreen/SKILL.md | 22 +-
site/.well-known/api-catalog | 14 +-
site/.well-known/mcp/server-card.json | 14 +-
site/.well-known/oauth-protected-resource | 4 +-
site/_redirects | 4 +
site/_worker.js | 2 +-
...> althing-vs-commercial-alternatives.html} | 106 ++--
... => althing-vs-commercial-alternatives.md} | 44 +-
site/cli-coverage.txt | 8 +-
site/docs/calibration/index.html | 68 +--
site/docs/calibration/index.md | 24 +-
site/docs/index.html | 76 +--
site/docs/index.md | 32 +-
site/docs/panel-run/index.html | 92 +--
site/docs/panel-run/index.md | 46 +-
site/generate-og-image.py | 18 +-
site/index.html | 116 ++--
site/index.html.j2 | 116 ++--
site/index.md | 50 +-
site/mcp/index.html | 220 +++----
site/mcp/index.md | 104 ++--
site/recommended-models/index.html | 74 +--
site/recommended-models/index.md | 30 +-
site/robots.txt | 2 +-
site/sitemap.xml | 14 +-
site/webmcp.js | 12 +-
.../synthpanel => skills/althing}/SKILL.md | 90 +--
skills/concept-test/SKILL.md | 24 +-
skills/focus-group/SKILL.md | 20 +-
skills/name-test/SKILL.md | 24 +-
skills/pricing-probe/SKILL.md | 22 +-
skills/survey-prescreen/SKILL.md | 22 +-
specs/sp-inline-calibration/questions.md | 32 +-
specs/sp-inline-calibration/research-map.md | 16 +-
.../research/instrument-dataset-coverage.md | 10 +-
.../research/synthbench-flow-map.md | 32 +-
specs/sp-pack-registry/questions.md | 10 +-
specs/sp-pack-registry/research-map.md | 14 +-
.../research/authoring-friction-evidence.md | 14 +-
.../research/pack-lifecycle-and-delivery.md | 28 +-
specs/sp-viz-layer/questions.md | 4 +-
specs/sp-viz-layer/research-map.md | 8 +-
.../research/cli-rendering-primitives.md | 4 +-
.../research/panel-json-schema.md | 20 +-
src/althing/__init__.py | 64 ++
src/althing/__main__.py | 9 +
src/althing/__version__.py | 1 +
src/{synth_panel => althing}/_runners.py | 38 +-
src/althing/agent_assets/__init__.py | 3 +
.../agent_assets/commands/althing-poll.md} | 14 +-
.../agent_assets/skills/althing}/SKILL.md | 90 +--
.../agent_assets/skills/concept-test/SKILL.md | 24 +-
.../agent_assets/skills/focus-group/SKILL.md | 20 +-
.../agent_assets/skills/name-test/SKILL.md | 24 +-
.../skills/pricing-probe/SKILL.md | 22 +-
.../skills/survey-prescreen/SKILL.md | 22 +-
src/{synth_panel => althing}/aggregation.py | 2 +-
.../analysis/__init__.py | 14 +-
.../analysis/distribution.py | 4 +-
.../analysis/inspect.py | 12 +-
.../analysis/subgroup.py | 4 +-
.../analysis/subgroup_cli.py | 8 +-
src/{synth_panel => althing}/analyze.py | 8 +-
.../attachments/__init__.py | 18 +-
.../attachments/filter.py | 4 +-
.../attachments/models.py | 2 +-
.../attachments/pdf.py | 8 +-
.../attachments/store.py | 6 +-
src/{synth_panel => althing}/calibration.py | 6 +-
src/{synth_panel => althing}/checkpoint.py | 16 +-
src/{synth_panel => althing}/cli/__init__.py | 0
src/{synth_panel => althing}/cli/commands.py | 336 +++++-----
.../cli/mcp_install.py | 38 +-
src/{synth_panel => althing}/cli/output.py | 2 +-
src/{synth_panel => althing}/cli/parser.py | 92 +--
src/{synth_panel => althing}/cli/progress.py | 2 +-
src/{synth_panel => althing}/cli/repl.py | 14 +-
src/{synth_panel => althing}/cli/slash.py | 6 +-
src/{synth_panel => althing}/conditions.py | 6 +-
src/{synth_panel => althing}/convergence.py | 14 +-
src/{synth_panel => althing}/cost.py | 8 +-
src/{synth_panel => althing}/cost_summary.py | 10 +-
src/{synth_panel => althing}/credentials.py | 34 +-
src/{synth_panel => althing}/data/__init__.py | 2 +-
.../data/synthbench-snapshot.json | 14 +-
src/{synth_panel => althing}/diff.py | 6 +-
src/{synth_panel => althing}/domains.py | 0
src/{synth_panel => althing}/ensemble.py | 30 +-
.../fetch/__init__.py | 2 +-
src/{synth_panel => althing}/fetch/cache.py | 4 +-
src/{synth_panel => althing}/fetch/ladder.py | 12 +-
src/{synth_panel => althing}/fetch/lower.py | 14 +-
.../fetch/perimeter.py | 6 +-
src/{synth_panel => althing}/instrument.py | 8 +-
src/althing/integrations/__init__.py | 21 +
.../integrations/composio.py | 44 +-
src/{synth_panel => althing}/llm/__init__.py | 6 +-
src/{synth_panel => althing}/llm/aliases.py | 12 +-
.../llm/capabilities.py | 4 +-
src/{synth_panel => althing}/llm/client.py | 34 +-
src/{synth_panel => althing}/llm/errors.py | 0
.../llm/fast_default.py | 0
src/{synth_panel => althing}/llm/models.py | 2 +-
src/althing/llm/providers/__init__.py | 18 +
.../llm/providers/_anthropic_format.py | 2 +-
.../llm/providers/_openai_format.py | 2 +-
.../llm/providers/anthropic.py | 32 +-
.../llm/providers/base.py | 6 +-
.../llm/providers/gemini.py | 10 +-
.../llm/providers/openai_compat.py | 8 +-
.../llm/providers/openrouter.py | 16 +-
.../llm/providers/xai.py | 8 +-
src/{synth_panel => althing}/llm/retry.py | 2 +-
.../logging_config.py | 20 +-
src/{synth_panel => althing}/main.py | 34 +-
src/althing/mcp/__init__.py | 7 +
src/{synth_panel => althing}/mcp/compat.py | 10 +-
src/{synth_panel => althing}/mcp/data.py | 34 +-
src/{synth_panel => althing}/mcp/sampling.py | 30 +-
src/{synth_panel => althing}/mcp/server.py | 136 ++---
src/{synth_panel => althing}/metadata.py | 14 +-
.../metadata_migrations.py | 12 +-
src/{synth_panel => althing}/orchestrator.py | 50 +-
src/{synth_panel => althing}/pack_diff.py | 4 +-
src/althing/packs/__init__.py | 3 +
.../packs/ai-eval-buyers.yaml | 0
.../packs/broad-professionals.yaml | 0
.../packs/developer.yaml | 0
.../packs/enterprise-ai-buyers.yaml | 0
.../packs/enterprise-buyer.yaml | 0
.../packs/general-consumer.yaml | 0
.../packs/healthcare-patient.yaml | 0
.../packs/instruments/__init__.py | 0
.../packs/instruments/churn-diagnosis.yaml | 2 +-
.../instruments/feature-prioritization.yaml | 2 +-
.../packs/instruments/general-survey.yaml | 2 +-
.../packs/instruments/happiness-probe.yaml | 2 +-
.../landing-page-comprehension.yaml | 2 +-
.../packs/instruments/market-research.yaml | 2 +-
.../packs/instruments/name-test.yaml | 2 +-
.../packs/instruments/pricing-discovery.yaml | 2 +-
.../packs/instruments/product-feedback.yaml | 2 +-
.../packs/job-seekers.yaml | 0
.../packs/market-research-critics.yaml | 0
.../packs/product-research.yaml | 0
.../packs/profiles/consumer.yaml | 0
.../packs/profiles/default.yaml | 2 +-
.../packs/profiles/research.yaml | 0
.../packs/recruiters-talent.yaml | 0
.../packs/skeptical-executives.yaml | 0
.../packs/startup-founder.yaml | 0
.../packs/students.yaml | 0
src/{synth_panel => althing}/persistence.py | 4 +-
src/{synth_panel => althing}/perturbation.py | 6 +-
.../plugins/__init__.py | 10 +-
src/{synth_panel => althing}/plugins/hooks.py | 6 +-
src/{synth_panel => althing}/plugins/lint.py | 4 +-
.../plugins/manager.py | 4 +-
.../plugins/manifest.py | 0
.../plugins/registry.py | 4 +-
src/{synth_panel => althing}/poll_summary.py | 6 +-
src/{synth_panel => althing}/preflight.py | 6 +-
src/{synth_panel => althing}/profiles.py | 8 +-
src/{synth_panel => althing}/prompts.py | 8 +-
src/{synth_panel => althing}/py.typed | 0
.../question_budget.py | 2 +-
.../registry/__init__.py | 8 +-
.../registry/cache.py | 18 +-
.../registry/fetch.py | 14 +-
.../registry/github.py | 6 +-
.../reporting/__init__.py | 4 +-
.../reporting/loader.py | 6 +-
.../reporting/markdown.py | 10 +-
.../response_coercion.py | 0
src/{synth_panel => althing}/routing.py | 2 +-
src/{synth_panel => althing}/runtime.py | 10 +-
.../schemas/__init__.py | 2 +-
.../schemas/v1.0.0.json | 4 +-
src/{synth_panel => althing}/sdk.py | 84 +--
src/{synth_panel => althing}/stats.py | 0
.../structured/__init__.py | 2 +-
.../structured/models.py | 6 +-
.../structured/output.py | 16 +-
.../structured/retry.py | 18 +-
.../structured/schemas.py | 4 +-
.../structured/validate.py | 2 +-
.../structured/verdict.py | 6 +-
src/{synth_panel => althing}/synthbench.py | 50 +-
.../synthbench_submit.py | 30 +-
src/{synth_panel => althing}/synthesis.py | 32 +-
.../synthesis_recovery.py | 12 +-
src/{synth_panel => althing}/templates.py | 4 +-
src/{synth_panel => althing}/text_width.py | 2 +-
src/synth_panel/__init__.py | 83 +--
src/synth_panel/__main__.py | 13 +-
src/synth_panel/__version__.py | 1 -
src/synth_panel/agent_assets/__init__.py | 3 -
src/synth_panel/integrations/__init__.py | 21 -
src/synth_panel/llm/providers/__init__.py | 18 -
src/synth_panel/mcp/__init__.py | 7 -
src/synth_panel/packs/__init__.py | 3 -
src/synthpanel/__init__.py | 85 ++-
src/synthpanel/__main__.py | 13 +-
tests/acceptance/test_registry_live.py | 8 +-
tests/attachments/__init__.py | 2 +-
tests/attachments/test_integration.py | 16 +-
tests/attachments/test_persistence.py | 16 +-
tests/conftest.py | 14 +-
.../reporting/map_reduce_per_question.json | 2 +-
tests/fixtures/reporting/rounds_shape.json | 2 +-
tests/mcp/test_decision_field_request.py | 10 +-
tests/mcp/test_decision_wiring.py | 54 +-
tests/mcp/test_instrument_vars.py | 18 +-
tests/mcp/test_max_cost.py | 90 +--
tests/mcp/test_response_envelopes.py | 56 +-
tests/mcp/test_response_gate.py | 10 +-
tests/mcp/test_verdict_emission.py | 36 +-
tests/orchestrator/test_flag_raising.py | 6 +-
tests/persistence/test_transcript_stamp.py | 4 +-
tests/schemas/test_v1_0_0_load.py | 2 +-
tests/structured/test_drift_contract.py | 38 +-
tests/structured/test_validate_envelope.py | 4 +-
tests/structured/test_verdict_shape.py | 8 +-
tests/test_abort_paths.py | 36 +-
tests/test_acceptance.py | 26 +-
tests/test_aggregation.py | 8 +-
tests/test_aliases.py | 44 +-
...thpanel_skill.py => test_althing_skill.py} | 20 +-
tests/test_analysis_pipeline.py | 4 +-
tests/test_analyze.py | 14 +-
tests/test_analyze_subgroup.py | 6 +-
tests/test_attachment_fetch_failure.py | 14 +-
tests/test_attachments.py | 14 +-
tests/test_attachments_caching.py | 10 +-
tests/test_attachments_filter.py | 10 +-
..._attachments_legacy_path_bypass_hq_ilke.py | 6 +-
tests/test_attachments_pdf.py | 12 +-
tests/test_attachments_v1_0_1_wiring.py | 24 +-
tests/test_attachments_v1_0_2_panel_shared.py | 2 +-
tests/test_best_model_for_cli.py | 18 +-
tests/test_broken_pipe.py | 26 +-
tests/test_calibration.py | 86 +--
tests/test_checkpoint.py | 92 +--
tests/test_claude_plugin_assets.py | 20 +-
tests/test_cli.py | 574 +++++++++---------
tests/test_cli_auth.py | 36 +-
tests/test_cli_report.py | 10 +-
tests/test_client.py | 20 +-
tests/test_compat_matrix.py | 8 +-
tests/test_conditions.py | 12 +-
tests/test_convergence_metric.py | 14 +-
tests/test_cost.py | 24 +-
tests/test_cost_actuals.py | 16 +-
tests/test_cost_gate.py | 28 +-
tests/test_cost_summary.py | 10 +-
tests/test_credentials.py | 76 +--
tests/test_doc_example_params.py | 4 +-
tests/test_domains.py | 14 +-
tests/test_ensemble.py | 190 +++---
tests/test_ensemble_public_api.py | 44 +-
tests/test_errors.py | 2 +-
tests/test_fast_default.py | 16 +-
tests/test_fetch.py | 10 +-
tests/test_fetch_lower.py | 16 +-
tests/test_inspect.py | 14 +-
tests/test_install_skills.py | 14 +-
tests/test_install_smoke.py | 24 +-
tests/test_instrument.py | 2 +-
tests/test_integrations_composio.py | 88 +--
tests/test_jinja2_prompts.py | 4 +-
tests/test_logging_config.py | 20 +-
tests/test_mcp_compat_grace.py | 46 +-
tests/test_mcp_data.py | 14 +-
tests/test_mcp_install.py | 248 ++++----
tests/test_mcp_sampling.py | 124 ++--
tests/test_mcp_server.py | 166 ++---
tests/test_mcp_stdio_sampling.py | 22 +-
tests/test_metadata.py | 10 +-
tests/test_models.py | 2 +-
.../test_openrouter_anthropic_passthrough.py | 12 +-
tests/test_orchestrator.py | 48 +-
tests/test_pack_calibrate.py | 52 +-
tests/test_pack_diff.py | 6 +-
tests/test_pack_import_gh.py | 36 +-
tests/test_persistence.py | 6 +-
tests/test_persona_llm_overrides.py | 8 +-
tests/test_persona_version_field.py | 4 +-
tests/test_personas_merge_collision.py | 48 +-
tests/test_perturbation.py | 8 +-
tests/test_plugin_lint.py | 14 +-
tests/test_plugins.py | 8 +-
tests/test_poll_summary.py | 18 +-
tests/test_preflight.py | 6 +-
tests/test_preflight_cli.py | 28 +-
tests/test_profiles.py | 6 +-
tests/test_progress.py | 20 +-
tests/test_providers.py | 214 +++----
tests/test_pydantic_roundtrip.py | 8 +-
tests/test_pyodide_install_shape.py | 32 +-
tests/test_question_failure_budget.py | 24 +-
tests/test_r4_cli_fixes.py | 40 +-
tests/test_rate_limit.py | 10 +-
tests/test_refresh_or_cost_table.py | 10 +-
tests/test_registry_cache.py | 18 +-
tests/test_registry_fetch.py | 6 +-
tests/test_registry_github_resolver.py | 6 +-
tests/test_repl_wiring.py | 62 +-
tests/test_reporting_loader.py | 8 +-
tests/test_reporting_markdown.py | 12 +-
tests/test_response_coercion.py | 4 +-
tests/test_response_schema_enforcement.py | 22 +-
tests/test_results_discovery.py | 34 +-
tests/test_retry_policy.py | 26 +-
tests/test_routing.py | 2 +-
tests/test_runs_diff.py | 4 +-
tests/test_runs_prune.py | 6 +-
tests/test_runtime.py | 8 +-
tests/test_schemas.py | 2 +-
tests/test_sdk.py | 166 ++---
tests/test_sdk_attachment_extraction.py | 10 +-
tests/test_seed.py | 26 +-
tests/test_site_api_catalog.py | 4 +-
tests/test_site_headers.py | 4 +-
tests/test_site_markdown.py | 8 +-
tests/test_site_tailwind.py | 2 +-
tests/test_site_version.py | 4 +-
tests/test_site_well_known.py | 4 +-
tests/test_skill_tool_conformance.py | 20 +-
tests/test_stats.py | 4 +-
tests/test_structured_models.py | 10 +-
tests/test_structured_output.py | 4 +-
tests/test_synthbench_contract.py | 18 +-
tests/test_synthbench_recommend.py | 62 +-
tests/test_synthbench_submit.py | 20 +-
tests/test_synthesis.py | 16 +-
tests/test_synthesis_failure.py | 80 +--
tests/test_synthesis_mapreduce.py | 8 +-
tests/test_synthesis_pyodide_mode.py | 16 +-
tests/test_synthesis_recovery.py | 102 ++--
tests/test_synthesis_strategy_interaction.py | 56 +-
tests/test_synthesis_subchunk.py | 20 +-
tests/test_synthesis_typed_partials.py | 22 +-
tests/test_synthpanel_shim.py | 80 +--
tests/test_templates.py | 6 +-
tests/test_text_width.py | 4 +-
tests/test_version_artifacts_in_sync.py | 16 +-
tests/test_vision_capability.py | 6 +-
tests/test_well_known_server_card.py | 10 +-
442 files changed, 5786 insertions(+), 5589 deletions(-)
rename commands/{synthpanel-poll.md => althing-poll.md} (85%)
rename docs/blog/{synthpanel-vs-commercial-alternatives.md => althing-vs-commercial-alternatives.md} (86%)
create mode 100644 shim-dist/README.md
create mode 100644 shim-dist/pyproject.toml
rename {src/synth_panel/agent_assets/skills/synthpanel => site/.well-known/agent-skills/althing}/SKILL.md (73%)
create mode 100644 site/_redirects
rename site/blog/{synthpanel-vs-commercial-alternatives.html => althing-vs-commercial-alternatives.html} (86%)
rename site/blog/{synthpanel-vs-commercial-alternatives.md => althing-vs-commercial-alternatives.md} (65%)
rename {site/.well-known/agent-skills/synthpanel => skills/althing}/SKILL.md (73%)
create mode 100644 src/althing/__init__.py
create mode 100644 src/althing/__main__.py
create mode 100644 src/althing/__version__.py
rename src/{synth_panel => althing}/_runners.py (96%)
create mode 100644 src/althing/agent_assets/__init__.py
rename src/{synth_panel/agent_assets/commands/synthpanel-poll.md => althing/agent_assets/commands/althing-poll.md} (85%)
rename {skills/synthpanel => src/althing/agent_assets/skills/althing}/SKILL.md (73%)
rename src/{synth_panel => althing}/agent_assets/skills/concept-test/SKILL.md (77%)
rename src/{synth_panel => althing}/agent_assets/skills/focus-group/SKILL.md (75%)
rename src/{synth_panel => althing}/agent_assets/skills/name-test/SKILL.md (65%)
rename src/{synth_panel => althing}/agent_assets/skills/pricing-probe/SKILL.md (75%)
rename src/{synth_panel => althing}/agent_assets/skills/survey-prescreen/SKILL.md (79%)
rename src/{synth_panel => althing}/aggregation.py (99%)
rename src/{synth_panel => althing}/analysis/__init__.py (71%)
rename src/{synth_panel => althing}/analysis/distribution.py (98%)
rename src/{synth_panel => althing}/analysis/inspect.py (98%)
rename src/{synth_panel => althing}/analysis/subgroup.py (97%)
rename src/{synth_panel => althing}/analysis/subgroup_cli.py (98%)
rename src/{synth_panel => althing}/analyze.py (99%)
rename src/{synth_panel => althing}/attachments/__init__.py (74%)
rename src/{synth_panel => althing}/attachments/filter.py (95%)
rename src/{synth_panel => althing}/attachments/models.py (96%)
rename src/{synth_panel => althing}/attachments/pdf.py (99%)
rename src/{synth_panel => althing}/attachments/store.py (94%)
rename src/{synth_panel => althing}/calibration.py (98%)
rename src/{synth_panel => althing}/checkpoint.py (98%)
rename src/{synth_panel => althing}/cli/__init__.py (100%)
rename src/{synth_panel => althing}/cli/commands.py (96%)
rename src/{synth_panel => althing}/cli/mcp_install.py (92%)
rename src/{synth_panel => althing}/cli/output.py (98%)
rename src/{synth_panel => althing}/cli/parser.py (94%)
rename src/{synth_panel => althing}/cli/progress.py (98%)
rename src/{synth_panel => althing}/cli/repl.py (90%)
rename src/{synth_panel => althing}/cli/slash.py (97%)
rename src/{synth_panel => althing}/conditions.py (97%)
rename src/{synth_panel => althing}/convergence.py (98%)
rename src/{synth_panel => althing}/cost.py (99%)
rename src/{synth_panel => althing}/cost_summary.py (97%)
rename src/{synth_panel => althing}/credentials.py (89%)
rename src/{synth_panel => althing}/data/__init__.py (80%)
rename src/{synth_panel => althing}/data/synthbench-snapshot.json (90%)
rename src/{synth_panel => althing}/diff.py (98%)
rename src/{synth_panel => althing}/domains.py (100%)
rename src/{synth_panel => althing}/ensemble.py (97%)
rename src/{synth_panel => althing}/fetch/__init__.py (96%)
rename src/{synth_panel => althing}/fetch/cache.py (98%)
rename src/{synth_panel => althing}/fetch/ladder.py (97%)
rename src/{synth_panel => althing}/fetch/lower.py (95%)
rename src/{synth_panel => althing}/fetch/perimeter.py (98%)
rename src/{synth_panel => althing}/instrument.py (99%)
create mode 100644 src/althing/integrations/__init__.py
rename src/{synth_panel => althing}/integrations/composio.py (90%)
rename src/{synth_panel => althing}/llm/__init__.py (78%)
rename src/{synth_panel => althing}/llm/aliases.py (91%)
rename src/{synth_panel => althing}/llm/capabilities.py (97%)
rename src/{synth_panel => althing}/llm/client.py (90%)
rename src/{synth_panel => althing}/llm/errors.py (100%)
rename src/{synth_panel => althing}/llm/fast_default.py (100%)
rename src/{synth_panel => althing}/llm/models.py (99%)
create mode 100644 src/althing/llm/providers/__init__.py
rename src/{synth_panel => althing}/llm/providers/_anthropic_format.py (99%)
rename src/{synth_panel => althing}/llm/providers/_openai_format.py (99%)
rename src/{synth_panel => althing}/llm/providers/anthropic.py (82%)
rename src/{synth_panel => althing}/llm/providers/base.py (89%)
rename src/{synth_panel => althing}/llm/providers/gemini.py (90%)
rename src/{synth_panel => althing}/llm/providers/openai_compat.py (92%)
rename src/{synth_panel => althing}/llm/providers/openrouter.py (96%)
rename src/{synth_panel => althing}/llm/providers/xai.py (91%)
rename src/{synth_panel => althing}/llm/retry.py (98%)
rename src/{synth_panel => althing}/logging_config.py (76%)
rename src/{synth_panel => althing}/main.py (91%)
create mode 100644 src/althing/mcp/__init__.py
rename src/{synth_panel => althing}/mcp/compat.py (91%)
rename src/{synth_panel => althing}/mcp/data.py (95%)
rename src/{synth_panel => althing}/mcp/sampling.py (93%)
rename src/{synth_panel => althing}/mcp/server.py (97%)
rename src/{synth_panel => althing}/metadata.py (94%)
rename src/{synth_panel => althing}/metadata_migrations.py (85%)
rename src/{synth_panel => althing}/orchestrator.py (98%)
rename src/{synth_panel => althing}/pack_diff.py (98%)
create mode 100644 src/althing/packs/__init__.py
rename src/{synth_panel => althing}/packs/ai-eval-buyers.yaml (100%)
rename src/{synth_panel => althing}/packs/broad-professionals.yaml (100%)
rename src/{synth_panel => althing}/packs/developer.yaml (100%)
rename src/{synth_panel => althing}/packs/enterprise-ai-buyers.yaml (100%)
rename src/{synth_panel => althing}/packs/enterprise-buyer.yaml (100%)
rename src/{synth_panel => althing}/packs/general-consumer.yaml (100%)
rename src/{synth_panel => althing}/packs/healthcare-patient.yaml (100%)
rename src/{synth_panel => althing}/packs/instruments/__init__.py (100%)
rename src/{synth_panel => althing}/packs/instruments/churn-diagnosis.yaml (99%)
rename src/{synth_panel => althing}/packs/instruments/feature-prioritization.yaml (99%)
rename src/{synth_panel => althing}/packs/instruments/general-survey.yaml (98%)
rename src/{synth_panel => althing}/packs/instruments/happiness-probe.yaml (98%)
rename src/{synth_panel => althing}/packs/instruments/landing-page-comprehension.yaml (99%)
rename src/{synth_panel => althing}/packs/instruments/market-research.yaml (98%)
rename src/{synth_panel => althing}/packs/instruments/name-test.yaml (99%)
rename src/{synth_panel => althing}/packs/instruments/pricing-discovery.yaml (99%)
rename src/{synth_panel => althing}/packs/instruments/product-feedback.yaml (98%)
rename src/{synth_panel => althing}/packs/job-seekers.yaml (100%)
rename src/{synth_panel => althing}/packs/market-research-critics.yaml (100%)
rename src/{synth_panel => althing}/packs/product-research.yaml (100%)
rename src/{synth_panel => althing}/packs/profiles/consumer.yaml (100%)
rename src/{synth_panel => althing}/packs/profiles/default.yaml (69%)
rename src/{synth_panel => althing}/packs/profiles/research.yaml (100%)
rename src/{synth_panel => althing}/packs/recruiters-talent.yaml (100%)
rename src/{synth_panel => althing}/packs/skeptical-executives.yaml (100%)
rename src/{synth_panel => althing}/packs/startup-founder.yaml (100%)
rename src/{synth_panel => althing}/packs/students.yaml (100%)
rename src/{synth_panel => althing}/persistence.py (99%)
rename src/{synth_panel => althing}/perturbation.py (98%)
rename src/{synth_panel => althing}/plugins/__init__.py (68%)
rename src/{synth_panel => althing}/plugins/hooks.py (96%)
rename src/{synth_panel => althing}/plugins/lint.py (98%)
rename src/{synth_panel => althing}/plugins/manager.py (98%)
rename src/{synth_panel => althing}/plugins/manifest.py (100%)
rename src/{synth_panel => althing}/plugins/registry.py (94%)
rename src/{synth_panel => althing}/poll_summary.py (99%)
rename src/{synth_panel => althing}/preflight.py (96%)
rename src/{synth_panel => althing}/profiles.py (97%)
rename src/{synth_panel => althing}/prompts.py (98%)
rename src/{synth_panel => althing}/py.typed (100%)
rename src/{synth_panel => althing}/question_budget.py (98%)
rename src/{synth_panel => althing}/registry/__init__.py (96%)
rename src/{synth_panel => althing}/registry/cache.py (91%)
rename src/{synth_panel => althing}/registry/fetch.py (88%)
rename src/{synth_panel => althing}/registry/github.py (97%)
rename src/{synth_panel => althing}/reporting/__init__.py (79%)
rename src/{synth_panel => althing}/reporting/loader.py (92%)
rename src/{synth_panel => althing}/reporting/markdown.py (97%)
rename src/{synth_panel => althing}/response_coercion.py (100%)
rename src/{synth_panel => althing}/routing.py (98%)
rename src/{synth_panel => althing}/runtime.py (98%)
rename src/{synth_panel => althing}/schemas/__init__.py (96%)
rename src/{synth_panel => althing}/schemas/v1.0.0.json (97%)
rename src/{synth_panel => althing}/sdk.py (96%)
rename src/{synth_panel => althing}/stats.py (100%)
rename src/{synth_panel => althing}/structured/__init__.py (52%)
rename src/{synth_panel => althing}/structured/models.py (94%)
rename src/{synth_panel => althing}/structured/output.py (96%)
rename src/{synth_panel => althing}/structured/retry.py (90%)
rename src/{synth_panel => althing}/structured/schemas.py (96%)
rename src/{synth_panel => althing}/structured/validate.py (99%)
rename src/{synth_panel => althing}/structured/verdict.py (96%)
rename src/{synth_panel => althing}/synthbench.py (94%)
rename src/{synth_panel => althing}/synthbench_submit.py (96%)
rename src/{synth_panel => althing}/synthesis.py (98%)
rename src/{synth_panel => althing}/synthesis_recovery.py (97%)
rename src/{synth_panel => althing}/templates.py (98%)
rename src/{synth_panel => althing}/text_width.py (98%)
delete mode 100644 src/synth_panel/__version__.py
delete mode 100644 src/synth_panel/agent_assets/__init__.py
delete mode 100644 src/synth_panel/integrations/__init__.py
delete mode 100644 src/synth_panel/llm/providers/__init__.py
delete mode 100644 src/synth_panel/mcp/__init__.py
delete mode 100644 src/synth_panel/packs/__init__.py
rename tests/{test_synthpanel_skill.py => test_althing_skill.py} (89%)
diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index 75e91735..32d30598 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,16 +1,16 @@
{
- "name": "synthpanel",
+ "name": "althing",
"version": "0.1.0",
"description": "Run synthetic focus groups and user research panels using AI personas. Define personas in YAML, design survey instruments, and collect structured qualitative feedback — all from Claude Code.",
"mcp_servers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": {}
}
},
"skills": [
- "skills/synthpanel/SKILL.md",
+ "skills/althing/SKILL.md",
"skills/focus-group/SKILL.md",
"skills/name-test/SKILL.md",
"skills/concept-test/SKILL.md",
diff --git a/.env.example b/.env.example
index d46a9d98..f1389d38 100644
--- a/.env.example
+++ b/.env.example
@@ -1,8 +1,8 @@
-# SynthPanel API Keys (set at least one)
+# Althing API Keys (set at least one)
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
GEMINI_API_KEY=
XAI_API_KEY=
OPENROUTER_API_KEY=
# Optional
-SYNTHPANEL_LOG_LEVEL=INFO
+ALTHING_LOG_LEVEL=INFO
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index e2fb2feb..3ab13e79 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -6,7 +6,7 @@ body:
id: version
attributes:
label: synth-panel version
- description: Output of `synthpanel --version` or the installed package version.
+ description: Output of `althing --version` or the installed package version.
placeholder: e.g. 0.7.4
validations:
required: true
@@ -42,7 +42,7 @@ body:
description: Minimal steps to reproduce. Include command, YAML input, or code snippet.
placeholder: |
1. Create `personas.yaml` with ...
- 2. Run `synthpanel panel run --personas personas.yaml --instrument ...`
+ 2. Run `althing panel run --personas personas.yaml --instrument ...`
3. Observe ...
validations:
required: true
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 8b241fa9..5cfbda73 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -33,7 +33,7 @@ Choose one (matches the auto-tag labels):
- [ ] Tests added or updated
- [ ] `ruff check src/ tests/` passes
-- [ ] `mypy src/synth_panel/` passes
+- [ ] `mypy src/althing/` passes
- [ ] CHANGELOG.md updated (if user-visible change)
- [ ] Commits signed off with `git commit -s` (see CONTRIBUTING.md)
diff --git a/.github/scripts/verify-ci-checks.sh b/.github/scripts/verify-ci-checks.sh
index cdb7fb92..57602484 100755
--- a/.github/scripts/verify-ci-checks.sh
+++ b/.github/scripts/verify-ci-checks.sh
@@ -13,7 +13,7 @@
# concurrency group cancels one of the twin runs — park a cancelled or
# failed run next to the successful same-named run, and those superseded
# runs never turn green. Counting all of them blocked SynthBench v0.3.1
-# (PR #334) and SynthPanel's first v1.6.0 attempt, forcing manual tags.
+# (PR #334) and Althing's first v1.6.0 attempt, forcing manual tags.
# Only the newest run per (app, name) reflects the commit's real status;
# GitHub's own merge box collapses check runs the same way.
#
diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml
index 5d04c31b..456191e4 100644
--- a/.github/workflows/auto-tag.yml
+++ b/.github/workflows/auto-tag.yml
@@ -131,9 +131,9 @@ jobs:
echo "tag=$NEW_TAG" >> "$GITHUB_OUTPUT"
echo "New tag: $NEW_TAG"
- # Sync src/synth_panel/__version__.py (and the rendered landing page,
+ # Sync src/althing/__version__.py (and the rendered landing page,
# which derives from it) to the new tag BEFORE tagging. pyproject.toml
- # uses `version = {attr = "synth_panel.__version__.__version__"}`, so
+ # uses `version = {attr = "althing.__version__.__version__"}`, so
# the build's package version is whatever this file says at the tagged
# SHA. Without this step, the tagged commit carries the previous
# version string and the resulting sdist/wheel is named after the
@@ -146,7 +146,7 @@ jobs:
NEW_TAG: ${{ steps.bump.outputs.tag }}
run: |
VERSION="${NEW_TAG#v}"
- printf '__version__ = "%s"\n' "$VERSION" > src/synth_panel/__version__.py
+ printf '__version__ = "%s"\n' "$VERSION" > src/althing/__version__.py
# Keep every committed artifact that embeds the version in
# lockstep. The v1.5.0 manual cut needed three follow-up PRs
# (#488 #489 #490) because only site/index.html was synced
@@ -170,7 +170,7 @@ jobs:
# Mint a token for the org-owned `dataviking-release-bot` App. The App is
# an Integration bypass actor on the main branch ruleset (see
- # dataviking-infra synthpanel.tf), so pushing the bump commit AS the App
+ # dataviking-infra althing.tf), so pushing the bump commit AS the App
# is allowed — whereas a github-actions[bot] / GITHUB_TOKEN push to main
# is rejected with GH013. This removed the manual "pre-bump the version in
# the PR" workaround (the escape-hatch branch below still works if a PR
@@ -204,7 +204,7 @@ jobs:
# drop a refreshed file from the bump commit. Root server.json
# is the second descriptor render_server_card.py rewrites —
# omitting it here left it drifted on main and bit PR #583.
- git add src/synth_panel/__version__.py site/index.html site/ \
+ git add src/althing/__version__.py site/index.html site/ \
site/.well-known/mcp/server-card.json server.json
if git diff --staged --quiet; then
echo "Version artifacts already at ${NEW_TAG} (pre-bumped in PR) — nothing to commit."
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4463bff7..c491a4fa 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -52,7 +52,7 @@ jobs:
run: pip install -e ".[dev,mcp]"
- name: Mypy
- run: mypy src/synth_panel/
+ run: mypy src/althing/
security:
runs-on: ubuntu-latest
@@ -76,7 +76,7 @@ jobs:
# Tracking: https://nvd.nist.gov/vuln/detail/CVE-2026-3219
# Tracking: https://nvd.nist.gov/vuln/detail/CVE-2026-6357
#
- # `--skip-editable` excludes the `synthpanel` package itself (installed
+ # `--skip-editable` excludes the `althing` package itself (installed
# via `pip install -e .`). The audit is meant to catch dependency
# vulnerabilities, not vulnerabilities in the package being audited —
# and the latter would also fail "not found on PyPI" on release commits
@@ -108,7 +108,7 @@ jobs:
run: pip install -e ".[dev,mcp]"
- name: Run tests with coverage
- run: pytest tests/ -x --ignore=tests/test_acceptance.py --cov=synth_panel --cov-report=term --cov-fail-under=80
+ run: pytest tests/ -x --ignore=tests/test_acceptance.py --cov=althing --cov-report=term --cov-fail-under=80
coverage:
runs-on: ubuntu-latest
@@ -128,7 +128,7 @@ jobs:
- name: Run tests with coverage
run: |
pytest tests/ --ignore=tests/test_acceptance.py \
- --cov=synth_panel --cov-report=term-missing --cov-report=html \
+ --cov=althing --cov-report=term-missing --cov-report=html \
| tee coverage-output.txt
- name: Coverage summary
@@ -220,9 +220,9 @@ jobs:
run: pip install -e ".[dev,mcp]"
- name: Install the real SynthBench harness (GitHub-only)
- # Installed after synthpanel so its `synthpanel>=0.2.0` dependency
+ # Installed after althing so its `althing>=0.2.0` dependency
# is already satisfied by the editable install and pip does not
- # pull a published synthpanel wheel over the checkout.
+ # pull a published althing wheel over the checkout.
run: pip install "synthbench @ git+https://github.com/DataViking-Tech/SynthBench.git"
- name: Run the submission contract tests against synthbench validate()
@@ -276,7 +276,7 @@ jobs:
done
clean-install-smoke:
- # sy-6kr: prove `pip install synthpanel` (no source checkout) yields
+ # sy-6kr: prove `pip install althing` (no source checkout) yields
# a working CLI from a fresh environment. The matrix exercises the
# two wheel-from-PyPI agent-onboarding paths (bare wheel, `[mcp]`
# extra); pipx gets its own job below. Failures here surface as
@@ -321,27 +321,27 @@ jobs:
set -euo pipefail
python -m venv /tmp/smoke
/tmp/smoke/bin/python -m pip install --upgrade pip
- WHEEL=$(ls dist/synthpanel-*.whl)
+ WHEEL=$(ls dist/althing-*.whl)
/tmp/smoke/bin/python -m pip install "${WHEEL}${{ matrix.install.extras }}"
- # No source directory is on the path — `synthpanel` resolves
+ # No source directory is on the path — `althing` resolves
# only via the wheel. If any of these fail, the install path
# is broken for new users.
- /tmp/smoke/bin/synthpanel --version
- /tmp/smoke/bin/synthpanel --help > /dev/null
- /tmp/smoke/bin/synthpanel whoami
+ /tmp/smoke/bin/althing --version
+ /tmp/smoke/bin/althing --help > /dev/null
+ /tmp/smoke/bin/althing whoami
# sy-e28: prove the no-credentials install-only mode works in a
# clean wheel install. Unset the fake key for this step so it
# actually exercises the "credentials missing" path; exit code
# must still be 0 because install_ok dominates.
- env -u ANTHROPIC_API_KEY /tmp/smoke/bin/synthpanel doctor --install-only
+ env -u ANTHROPIC_API_KEY /tmp/smoke/bin/althing doctor --install-only
- /tmp/smoke/bin/synthpanel doctor
+ /tmp/smoke/bin/althing doctor
# `[mcp]` matrix entry must additionally import the MCP server.
if [ -n "${{ matrix.install.extras }}" ]; then
- /tmp/smoke/bin/python -c "from synth_panel.mcp.server import mcp; print('mcp server import OK')"
+ /tmp/smoke/bin/python -c "from althing.mcp.server import mcp; print('mcp server import OK')"
fi
clean-install-pipx:
@@ -373,13 +373,13 @@ jobs:
set -euo pipefail
pip install --upgrade pipx
python -m pipx ensurepath
- WHEEL=$(ls dist/synthpanel-*.whl)
+ WHEEL=$(ls dist/althing-*.whl)
# `--python` keeps pipx pinned to the runner's 3.14; the default
# would otherwise reach for the system python.
python -m pipx install --python "$(which python)" "${WHEEL}"
# pipx installs to ~/.local/bin by default.
export PATH="$HOME/.local/bin:$PATH"
- synthpanel --version
- synthpanel --help > /dev/null
- synthpanel whoami
- synthpanel doctor
+ althing --version
+ althing --help > /dev/null
+ althing whoami
+ althing doctor
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index bc1c0722..541dd079 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -107,7 +107,7 @@ jobs:
IS_STABLE: ${{ steps.ref.outputs.is_stable }}
run: |
set -euo pipefail
- IMAGES=("ghcr.io/dataviking-tech/synthpanel")
+ IMAGES=("ghcr.io/dataviking-tech/althing")
MAJOR="${VERSION%%.*}"
REST="${VERSION#*.}"
MINOR="${REST%%.*}"
@@ -148,7 +148,7 @@ jobs:
push: true
tags: ${{ steps.tags.outputs.tags }}
build-args: |
- SYNTHPANEL_VERSION=${{ steps.ref.outputs.version }}
+ ALTHING_VERSION=${{ steps.ref.outputs.version }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ steps.ref.outputs.build_date }}
provenance: true
@@ -163,7 +163,7 @@ jobs:
TAGS: ${{ steps.tags.outputs.tags }}
run: |
{
- echo "## Pushed synthpanel ${VERSION}"
+ echo "## Pushed althing ${VERSION}"
echo ""
echo "**Digest:** \`${DIGEST}\`"
echo ""
@@ -175,7 +175,7 @@ jobs:
echo ""
echo "**Try it:**"
echo '```bash'
- echo "docker pull ghcr.io/dataviking-tech/synthpanel:${VERSION}"
- echo "docker run --rm -e ANTHROPIC_API_KEY=\$KEY ghcr.io/dataviking-tech/synthpanel:${VERSION} prompt 'hello'"
+ echo "docker pull ghcr.io/dataviking-tech/althing:${VERSION}"
+ echo "docker run --rm -e ANTHROPIC_API_KEY=\$KEY ghcr.io/dataviking-tech/althing:${VERSION} prompt 'hello'"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
diff --git a/.github/workflows/publish-test.yml b/.github/workflows/publish-test.yml
index 8c3d07bc..9395408b 100644
--- a/.github/workflows/publish-test.yml
+++ b/.github/workflows/publish-test.yml
@@ -1,15 +1,15 @@
name: Publish Dev to TestPyPI
# Every merge to main publishes a dev build to test.pypi.org.
-# Version is auto-generated: {src/synth_panel/__version__.py version}.dev{run_number}
+# Version is auto-generated: {src/althing/__version__.py version}.dev{run_number}
#
# ONE-TIME MANUAL SETUP (required before the first successful publish):
#
# 1. On https://test.pypi.org/manage/account/publishing/ add a trusted
# publisher with:
-# project name = synthpanel
+# project name = althing
# owner = DataViking-Tech
-# repo = synthpanel
+# repo = althing
# workflow = publish-test.yml
# environment = pypi-test (must match the `environment:` key below)
# 2. In GitHub repo Settings -> Environments, create an environment
@@ -48,18 +48,18 @@ jobs:
run: |
set -euo pipefail
# pyproject.toml declares `dynamic = ["version"]` and reads the
- # version from src/synth_panel/__version__.py, so that file — not
+ # version from src/althing/__version__.py, so that file — not
# pyproject.toml — is what must be rewritten here. The previous
# pyproject-based sed silently no-oped after the dynamic-version
# migration and every push re-uploaded the same wheel, which
# TestPyPI rejected with "400 File already exists".
- BASE=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' src/synth_panel/__version__.py)
+ BASE=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' src/althing/__version__.py)
if [ -z "$BASE" ]; then
- echo "::error::Could not read base version from src/synth_panel/__version__.py"
+ echo "::error::Could not read base version from src/althing/__version__.py"
exit 1
fi
DEV_VERSION="${BASE}.dev${GITHUB_RUN_NUMBER}"
- printf '__version__ = "%s"\n' "$DEV_VERSION" > src/synth_panel/__version__.py
+ printf '__version__ = "%s"\n' "$DEV_VERSION" > src/althing/__version__.py
echo "version=$DEV_VERSION" >> "$GITHUB_OUTPUT"
echo "Dev version: $DEV_VERSION"
@@ -89,8 +89,8 @@ jobs:
DEV_VERSION: ${{ steps.version.outputs.version }}
run: |
{
- echo "## Published synthpanel ${DEV_VERSION} (dev)"
+ echo "## Published althing ${DEV_VERSION} (dev)"
echo ""
- echo "- TestPyPI: https://test.pypi.org/project/synthpanel/${DEV_VERSION}/"
- echo "- Install: \`pip install -i https://test.pypi.org/simple/ synthpanel==${DEV_VERSION}\`"
+ echo "- TestPyPI: https://test.pypi.org/project/althing/${DEV_VERSION}/"
+ echo "- Install: \`pip install -i https://test.pypi.org/simple/ althing==${DEV_VERSION}\`"
} >> "$GITHUB_STEP_SUMMARY"
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 1a065894..7adcf86c 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -4,9 +4,9 @@ name: Publish to PyPI
# No API token required — PyPI verifies the workflow identity via OIDC.
#
# Trusted publisher must be registered at
-# https://pypi.org/manage/project/synthpanel/settings/publishing/ with:
+# https://pypi.org/manage/project/althing/settings/publishing/ with:
# owner = DataViking-Tech
-# repo = SynthPanel
+# repo = Althing
# workflow = publish.yml
# environment = pypi
#
@@ -29,7 +29,7 @@ permissions:
contents: read
concurrency:
- group: python-publish-synthpanel-${{ github.ref }}
+ group: python-publish-althing-${{ github.ref }}
cancel-in-progress: false
jobs:
@@ -57,6 +57,12 @@ jobs:
- name: Build sdist and wheel
run: python -m build
+ - name: Build synthpanel shim dist (rename transition)
+ # Metapackage that keeps `pip install synthpanel` working by
+ # depending on althing. Built into the same dist/ so the publish
+ # step uploads both; PyPI routes each file to its own project.
+ run: python -m build --outdir dist/ shim-dist/
+
- name: Show built artifacts
run: ls -lh dist/
@@ -72,8 +78,8 @@ jobs:
REF: ${{ github.ref_name }}
run: |
{
- echo "## Published synthpanel ${REF#v}"
+ echo "## Published althing ${REF#v}"
echo ""
- echo "- PyPI: https://pypi.org/project/synthpanel/${REF#v}/"
- echo "- Install: \`pip install synthpanel==${REF#v}\`"
+ echo "- PyPI: https://pypi.org/project/althing/${REF#v}/"
+ echo "- Install: \`pip install althing==${REF#v}\`"
} >> "$GITHUB_STEP_SUMMARY"
diff --git a/.gitignore b/.gitignore
index 618e627d..bfc0bf54 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,8 +32,8 @@ state.json
gastown-*.json
CLAUDE.local.md
-# synthpanel data
-.synthpanel/
+# althing data
+.althing/
sessions/
# Testing
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59199dd5..85538bed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,29 @@
# Changelog
-All notable changes to synthpanel are documented here.
+All notable changes to althing (formerly synthpanel) are documented here.
For auto-generated release notes, see [GitHub Releases](https://github.com/DataViking-Tech/SynthPanel/releases).
## [Unreleased]
+### Changed
+
+- **Renamed: synthpanel → althing.** The project is now **Althing**
+ (althing.dev) — named for the Norse general assembly. Everything ships
+ under the new name: PyPI distribution `althing`, canonical import
+ `import althing` (retiring the historical `synth_panel`-vs-`synthpanel`
+ module split from #509), CLI `althing`, env vars `ALTHING_*`, container
+ `ghcr.io/dataviking-tech/althing`, and site https://althing.dev.
+ Compatibility for one deprecation cycle, removed next major release:
+ - `import synthpanel` and `import synth_panel` still work (shim modules
+ that re-export `althing`, with a `DeprecationWarning`)
+ - the `synthpanel` console script still works (prints a rename notice)
+ - `SYNTHPANEL_*` environment variables are honored when the `ALTHING_*`
+ equivalent is unset (one-time `DeprecationWarning`)
+ - `pip install synthpanel` remains published as a shim distribution that
+ depends on `althing`
+ Historical changelog entries below retain the old name.
+
### Added
- **`cost show `.** Per-run cost breakdown for one saved
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e18a0b83..70c60d3c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-# Contributing to synthpanel
+# Contributing to althing
## Development Setup
@@ -8,12 +8,12 @@ access, which is granted on request (see [Submitting Changes](#submitting-change
```bash
# Standard contributor flow — fork, then clone your fork:
-gh repo fork DataViking-Tech/SynthPanel --clone
-cd SynthPanel
+gh repo fork DataViking-Tech/Althing --clone
+cd Althing
# (Maintainers and granted collaborators only — direct clone of upstream)
-# git clone https://github.com/DataViking-Tech/SynthPanel.git
-# cd SynthPanel
+# git clone https://github.com/DataViking-Tech/Althing.git
+# cd Althing
# Create a virtual environment (using uv or standard venv)
uv venv .venv && source .venv/bin/activate
@@ -58,7 +58,7 @@ ruff check --fix src/ tests/
## Type Checking
```bash
-mypy src/synth_panel/
+mypy src/althing/
```
## Running the MCP Server Locally
@@ -66,7 +66,7 @@ mypy src/synth_panel/
The MCP server uses stdio transport and is designed to be launched by an MCP-aware editor (Claude Code, Cursor, Windsurf, etc.):
```bash
-synthpanel mcp-serve
+althing mcp-serve
```
For testing outside an editor, you can pipe JSON-RPC messages to stdin. See [docs/mcp.md](docs/mcp.md) for the full tool/resource/prompt reference.
@@ -74,13 +74,13 @@ For testing outside an editor, you can pipe JSON-RPC messages to stdin. See [doc
## Running Without Installing
```bash
-PYTHONPATH=src python3 -m synth_panel prompt "Hello"
+PYTHONPATH=src python3 -m althing prompt "Hello"
```
## Project Structure
```
-src/synth_panel/
+src/althing/
├── llm/ # Provider-agnostic LLM client
│ ├── client.py # Unified send/stream interface
│ ├── aliases.py # Model alias resolution
@@ -101,16 +101,16 @@ src/synth_panel/
## Adding a New LLM Provider
-Adapters are the highest-leverage contribution — one adapter brings every synthpanel feature to a new backend. See [docs/adapter-guide.md](docs/adapter-guide.md) for a step-by-step walkthrough, including a worked Mistral example, required tests, and PR checklist.
+Adapters are the highest-leverage contribution — one adapter brings every althing feature to a new backend. See [docs/adapter-guide.md](docs/adapter-guide.md) for a step-by-step walkthrough, including a worked Mistral example, required tests, and PR checklist.
## Submitting Changes
-1. Fork the repository (`gh repo fork DataViking-Tech/SynthPanel --clone`).
+1. Fork the repository (`gh repo fork DataViking-Tech/Althing --clone`).
2. Create a feature branch from `main` on your fork: `git checkout -b feat/my-change`.
3. Make your changes. Add tests for new functionality.
4. Run the test suite: `pytest tests/`
5. Run lint: `ruff check src/ tests/`
-6. Push to your fork and open a pull request against `DataViking-Tech/SynthPanel:main`.
+6. Push to your fork and open a pull request against `DataViking-Tech/Althing:main`.
If you're contributing regularly and want to push branches directly to upstream
instead of working from a fork, open a regular issue requesting collaborator
diff --git a/Dockerfile b/Dockerfile
index 8f6554e8..57d5836d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,18 +1,18 @@
# syntax=docker/dockerfile:1.23
#
-# Production runtime image for synthpanel.
+# Production runtime image for althing.
#
# This image is sized for ephemeral / serverless invocation (Lambda, Cloud Run,
# GitHub Actions, n8n, etc.) — small footprint, no editor tooling.
#
-# Default CMD launches the MCP server on stdio. Override with any synthpanel
+# Default CMD launches the MCP server on stdio. Override with any althing
# subcommand:
#
-# docker run --rm -e ANTHROPIC_API_KEY=$KEY synthpanel/synthpanel \
+# docker run --rm -e ANTHROPIC_API_KEY=$KEY althing/althing \
# prompt "Say hello"
#
# Build:
-# docker build -t synthpanel:local .
+# docker build -t althing:local .
#
# Multi-arch builds happen in CI via .github/workflows/docker.yml.
@@ -42,18 +42,18 @@ RUN python -m build --wheel --outdir /build/dist
# ---------- runtime ----------
FROM python:${PYTHON_VERSION}-slim AS runtime
-ARG SYNTHPANEL_VERSION=unknown
+ARG ALTHING_VERSION=unknown
ARG VCS_REF=unknown
ARG BUILD_DATE=unknown
-LABEL org.opencontainers.image.title="synthpanel" \
+LABEL org.opencontainers.image.title="althing" \
org.opencontainers.image.description="Run synthetic focus groups using AI personas. CLI, Python library, and MCP server." \
- org.opencontainers.image.url="https://synthpanel.dev" \
- org.opencontainers.image.documentation="https://github.com/DataViking-Tech/SynthPanel#readme" \
- org.opencontainers.image.source="https://github.com/DataViking-Tech/SynthPanel" \
+ org.opencontainers.image.url="https://althing.dev" \
+ org.opencontainers.image.documentation="https://github.com/DataViking-Tech/Althing#readme" \
+ org.opencontainers.image.source="https://github.com/DataViking-Tech/Althing" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.vendor="DataViking-Tech" \
- org.opencontainers.image.version="${SYNTHPANEL_VERSION}" \
+ org.opencontainers.image.version="${ALTHING_VERSION}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.opencontainers.image.created="${BUILD_DATE}"
@@ -65,8 +65,8 @@ ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
# Non-root user — Lambda and Cloud Run both honor USER, and avoiding root
# is good practice for any ephemeral container. UID 1000 (not --system) so
# bind mounts from host UID 1000 are writable in dev workflows.
-RUN groupadd --gid 1000 synthpanel \
- && useradd --uid 1000 --gid synthpanel --create-home --home-dir /home/synthpanel synthpanel
+RUN groupadd --gid 1000 althing \
+ && useradd --uid 1000 --gid althing --create-home --home-dir /home/althing althing
# Install runtime dependencies BEFORE copying the wheel so this expensive
# layer caches across source-only changes. The wheel content changes on
@@ -83,14 +83,14 @@ RUN pip install --no-cache-dir $(python -c "import tomllib; d = tomllib.load(ope
# trip on the wheel filename's metadata.
COPY --from=builder /build/dist/*.whl /tmp/
RUN set -eux \
- && wheel="$(ls /tmp/synthpanel-*.whl | head -n1)" \
+ && wheel="$(ls /tmp/althing-*.whl | head -n1)" \
&& pip install --no-deps "${wheel}" \
- && rm -f /tmp/synthpanel-*.whl
+ && rm -f /tmp/althing-*.whl
-USER synthpanel
-WORKDIR /home/synthpanel
+USER althing
+WORKDIR /home/althing
# stdin must stay open for the MCP stdio transport. Callers running
# non-MCP subcommands can ignore this — it's only meaningful for mcp-serve.
-ENTRYPOINT ["synthpanel"]
+ENTRYPOINT ["althing"]
CMD ["mcp-serve"]
diff --git a/README.md b/README.md
index 7a2e6c5b..6e0a00e3 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,16 @@
-# synthpanel
+# althing
-[](https://pypi.org/project/synthpanel/)
-[](https://github.com/DataViking-Tech/SynthPanel/actions/workflows/ci.yml)
+[](https://pypi.org/project/althing/)
+[](https://github.com/DataViking-Tech/Althing/actions/workflows/ci.yml)
[](LICENSE)
-[](https://pypi.org/project/synthpanel/)
-[](https://github.com/DataViking-Tech/SynthPanel/blob/main/docs/mcp.md)
-[](https://github.com/DataViking-Tech/SynthPanel/pkgs/container/synthpanel)
+[](https://pypi.org/project/althing/)
+[](https://github.com/DataViking-Tech/Althing/blob/main/docs/mcp.md)
+[](https://github.com/DataViking-Tech/Althing/pkgs/container/althing)
[](https://ko-fi.com/dataviking)
-Site: · Benchmark:
+Site: · Benchmark:
-**SynthPanel is the synthetic-population MCP server for AI agents.**
+**Althing is the synthetic-population MCP server for AI agents.**
When your agent needs to know what a representative slice of humans would say
about a decision — pricing, naming, friction points, copy — it makes one tool
@@ -57,7 +57,7 @@ SDK.
> **Note (v1.0.6):** the v1.0.0 `panel_verdict` artifact (`headline`,
> `convergence`, `dissent_count`, `flags[]`, `schema_version`) defined in
-> [`schemas/v1.0.0.json`](src/synth_panel/schemas/v1.0.0.json) is now **emitted
+> [`schemas/v1.0.0.json`](src/althing/schemas/v1.0.0.json) is now **emitted
> on the success path** of the MCP panel tools (`run_panel`, `run_quick_poll`,
> `extend_panel` in BYOK mode): it rides under the envelope's `panel_verdict`
> key alongside the `synthesis` block above, and the response gate validates it
@@ -67,11 +67,11 @@ SDK.
> the typed envelope (`error_code`, `schema_version`, `retry_safe`).
```bash
-pip install synthpanel
+pip install althing
```
**Frozen contract:** the v1.0.0 schema lives in the package at
-[`synthpanel/schemas/v1.0.0.json`](src/synth_panel/schemas/v1.0.0.json) and is
+[`althing/schemas/v1.0.0.json`](src/althing/schemas/v1.0.0.json) and is
echoed on every persisted-panel success envelope and every typed error
(`schema_version: "1.0.0"`). Field-by-field reference:
[docs/response-contract.md](docs/response-contract.md). Migrating from v0.12?
@@ -160,43 +160,43 @@ matches how you use Python tools:
| Path | When | Command |
|------|------|---------|
-| **pip** (in your project venv) | You're integrating SynthPanel as a library | `pip install synthpanel` |
-| **pip + MCP** (in your project venv) | You also want the MCP server for agent integration | `pip install 'synthpanel[mcp]'` |
-| **pipx** (global, isolated) | You want `synthpanel` on your PATH without polluting any project | `pipx install synthpanel` |
-| **uvx** (zero-install) | You just want to run it once — no install at all | `uvx --from synthpanel synthpanel --help` |
-| **source** (latest unreleased) | You want main-branch fixes ahead of the next PyPI cut | `pip install git+https://github.com/DataViking-Tech/SynthPanel.git@main` |
+| **pip** (in your project venv) | You're integrating Althing as a library | `pip install althing` |
+| **pip + MCP** (in your project venv) | You also want the MCP server for agent integration | `pip install 'althing[mcp]'` |
+| **pipx** (global, isolated) | You want `althing` on your PATH without polluting any project | `pipx install althing` |
+| **uvx** (zero-install) | You just want to run it once — no install at all | `uvx --from althing althing --help` |
+| **source** (latest unreleased) | You want main-branch fixes ahead of the next PyPI cut | `pip install git+https://github.com/DataViking-Tech/Althing.git@main` |
After installing, verify the CLI is on your PATH and the runtime is sane
*before* configuring providers:
```bash
-synthpanel --version # smoke: package metadata + entry point dispatch
-synthpanel doctor --install-only # install health only — no credentials needed
-synthpanel doctor # full preflight (install + credentials)
-synthpanel whoami # which providers (if any) have credentials
+althing --version # smoke: package metadata + entry point dispatch
+althing doctor --install-only # install health only — no credentials needed
+althing doctor # full preflight (install + credentials)
+althing whoami # which providers (if any) have credentials
```
### Package vs. module name
-The PyPI distribution and CLI entry point are spelled **`synthpanel`** (one
+The PyPI distribution and CLI entry point are spelled **`althing`** (one
word). The importable Python module — the historical PEP 8 spelling — is
-**`synth_panel`** (two words, snake_case):
+**`althing`** (two words, snake_case):
```python
-import synth_panel # canonical
-from synth_panel import run_panel, sdk # library use
+import althing # canonical
+from althing import run_panel, sdk # library use
```
```bash
-synthpanel --version # CLI
-python -m synth_panel --version # canonical module form
-python -m synthpanel --version # one-word alias also works (sy-het)
+althing --version # CLI
+python -m althing --version # canonical module form
+python -m althing --version # one-word alias also works (sy-het)
```
-Both spellings resolve to the same code. The one-word `synthpanel` module
+Both spellings resolve to the same code. The one-word `althing` module
is a thin shim (`__path__` redirect + ``__main__.py``) shipped so agents
that guess `python -m ` don't hit a wall. New code should still
-prefer `import synth_panel` — it's what `__all__`, the docs, and the
+prefer `import althing` — it's what `__all__`, the docs, and the
schemas refer to.
`doctor` exits non-zero with actionable guidance when something's
@@ -206,8 +206,8 @@ it's the canonical "did the install land cleanly?" check, and
wheel on every push, so all three commands are part of the supported
contract.
-Use `synthpanel doctor --install-only` immediately after `pip install
-synthpanel` to validate the package, dependencies, and bundled packs
+Use `althing doctor --install-only` immediately after `pip install
+althing` to validate the package, dependencies, and bundled packs
without provisioning a provider key — exit 0 in that mode means the
install is healthy, even when credentials are not yet configured. The
JSON output (`--output-format json doctor --install-only`) separates
@@ -216,94 +216,94 @@ can branch on each surface independently.
Then provide an API key (Claude, OpenAI, Gemini, xAI, or any
OpenAI-compatible provider) — either export it in your shell or persist
-it once via `synthpanel login`:
+it once via `althing login`:
```bash
export ANTHROPIC_API_KEY="sk-..."
# or
-synthpanel login --provider anthropic --api-key sk-... # stored at
-# ~/.config/synthpanel/credentials.json, mode 0600
-synthpanel whoami
+althing login --provider anthropic --api-key sk-... # stored at
+# ~/.config/althing/credentials.json, mode 0600
+althing whoami
# Run a single prompt
-synthpanel prompt "What do you think of the name Traitprint for a career app?"
+althing prompt "What do you think of the name Traitprint for a career app?"
# Run a full panel
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml
```
## Works with
-SynthPanel is **MCP-native** — it ships an MCP server, and every major
+Althing is **MCP-native** — it ships an MCP server, and every major
agent framework now supports MCP as a first-class tool source. That
-means SynthPanel works out of the box with any framework that speaks
+means Althing works out of the box with any framework that speaks
MCP, with zero framework-specific wrapper packages to install. Runnable
examples for each framework live in
[`examples/integrations/`](examples/integrations/README.md).
| Framework | Example | Bridge | One-line install |
|-----------|---------|--------|------------------|
-| [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/mcp/) | [openai_agents.py](examples/integrations/openai_agents.py) | Built-in `MCPServerStdio` | `pip install openai-agents synthpanel[mcp]` |
-| [LlamaIndex](https://docs.llamaindex.ai/) | [llamaindex_tool.py](examples/integrations/llamaindex_tool.py) | `llama-index-tools-mcp` | `pip install llama-index-tools-mcp llama-index-llms-anthropic synthpanel[mcp]` |
-| [CrewAI](https://docs.crewai.com/) | [crewai_tool.py](examples/integrations/crewai_tool.py) | `crewai-tools[mcp]` | `pip install "crewai-tools[mcp]" crewai synthpanel[mcp]` |
-| [LangChain](https://python.langchain.com/) | [langchain_tool.py](examples/integrations/langchain_tool.py) | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langchain-anthropic synthpanel[mcp]` |
-| [LangGraph](https://langchain-ai.github.io/langgraph/) | [langchain_tool.py](examples/integrations/langchain_tool.py) | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langgraph langchain-anthropic synthpanel[mcp]` |
-| [Microsoft Agent Framework 1.0](https://learn.microsoft.com/en-us/agent-framework/) | [microsoft_agent.py](examples/integrations/microsoft_agent.py) | Built-in `MCPStdioTool` | `pip install agent-framework synthpanel[mcp]` |
-| [n8n](https://n8n.io/) | [n8n_workflow.json](examples/integrations/n8n_workflow.json) | Built-in MCP Client tool | `pip install synthpanel[mcp]` on the n8n runner |
-| [LangChain via Composio](https://composio.dev/) | [composio_langchain.py](examples/integrations/composio_langchain.py) | `synth_panel.integrations.composio` (in-process, non-MCP) | `pip install composio composio_langchain langchain langchain-anthropic synthpanel` |
-| [CrewAI via Composio](https://composio.dev/) | [composio_crewai.py](examples/integrations/composio_crewai.py) | `synth_panel.integrations.composio` (in-process, non-MCP) | `pip install composio composio_crewai crewai synthpanel` |
+| [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/mcp/) | [openai_agents.py](examples/integrations/openai_agents.py) | Built-in `MCPServerStdio` | `pip install openai-agents althing[mcp]` |
+| [LlamaIndex](https://docs.llamaindex.ai/) | [llamaindex_tool.py](examples/integrations/llamaindex_tool.py) | `llama-index-tools-mcp` | `pip install llama-index-tools-mcp llama-index-llms-anthropic althing[mcp]` |
+| [CrewAI](https://docs.crewai.com/) | [crewai_tool.py](examples/integrations/crewai_tool.py) | `crewai-tools[mcp]` | `pip install "crewai-tools[mcp]" crewai althing[mcp]` |
+| [LangChain](https://python.langchain.com/) | [langchain_tool.py](examples/integrations/langchain_tool.py) | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langchain-anthropic althing[mcp]` |
+| [LangGraph](https://langchain-ai.github.io/langgraph/) | [langchain_tool.py](examples/integrations/langchain_tool.py) | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langgraph langchain-anthropic althing[mcp]` |
+| [Microsoft Agent Framework 1.0](https://learn.microsoft.com/en-us/agent-framework/) | [microsoft_agent.py](examples/integrations/microsoft_agent.py) | Built-in `MCPStdioTool` | `pip install agent-framework althing[mcp]` |
+| [n8n](https://n8n.io/) | [n8n_workflow.json](examples/integrations/n8n_workflow.json) | Built-in MCP Client tool | `pip install althing[mcp]` on the n8n runner |
+| [LangChain via Composio](https://composio.dev/) | [composio_langchain.py](examples/integrations/composio_langchain.py) | `althing.integrations.composio` (in-process, non-MCP) | `pip install composio composio_langchain langchain langchain-anthropic althing` |
+| [CrewAI via Composio](https://composio.dev/) | [composio_crewai.py](examples/integrations/composio_crewai.py) | `althing.integrations.composio` (in-process, non-MCP) | `pip install composio composio_crewai crewai althing` |
Also reaches [Zapier MCP](https://zapier.com/mcp) (30K+ actions), the
[VS Code AI Toolkit](https://code.visualstudio.com/api/extension-guides/ai/mcp),
Windsurf, Cursor, Zed, Claude Code, and Claude Desktop via the same MCP
-server — all clients in that list install SynthPanel with
-`pip install synthpanel[mcp]` and a one-line MCP config entry (see
+server — all clients in that list install Althing with
+`pip install althing[mcp]` and a one-line MCP config entry (see
[Use with Claude Code / Cursor / Windsurf / Zed](#use-with-claude-code--cursor--windsurf--zed)).
> **Don't see your framework?** MCP bridges are available for nearly
> every major agent framework. Start from
> [`examples/integrations/README.md`](examples/integrations/README.md)
> — the pattern is identical in each case (point the client at
-> `synthpanel mcp-serve` over stdio) — or
-> [file an issue](https://github.com/DataViking-Tech/SynthPanel/issues)
+> `althing mcp-serve` over stdio) — or
+> [file an issue](https://github.com/DataViking-Tech/Althing/issues)
> so we can add a sibling example.
## Run via Docker
A pre-built image is published to both
-[GitHub Container Registry](https://github.com/DataViking-Tech/SynthPanel/pkgs/container/synthpanel)
+[GitHub Container Registry](https://github.com/DataViking-Tech/Althing/pkgs/container/althing)
and Docker Hub on every tagged release. Use it for ephemeral or serverless
invocation (Lambda, Cloud Run, GitHub Actions, n8n) where you'd rather
spin up a container than pip-install.
```bash
# Pull (either registry works — same image, multi-arch: amd64 + arm64)
-docker pull ghcr.io/dataviking-tech/synthpanel:latest
-docker pull synthpanel/synthpanel:latest
+docker pull ghcr.io/dataviking-tech/althing:latest
+docker pull althing/althing:latest
# One-off prompt
docker run --rm \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
- synthpanel/synthpanel \
+ althing/althing \
prompt "What makes a name feel trustworthy?"
# MCP server on stdio (default CMD — wire this into an agent's MCP config)
docker run --rm -i \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
- synthpanel/synthpanel
+ althing/althing
# Panel run with a mounted instrument file
docker run --rm \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
-v "$PWD":/work -w /work \
- synthpanel/synthpanel \
+ althing/althing \
panel run --personas personas.yaml --instrument survey.yaml
```
The image's default `CMD` is `mcp-serve`, so omitting the command starts
-the MCP stdio server. Any `synthpanel` subcommand can be passed as
+the MCP stdio server. Any `althing` subcommand can be passed as
arguments to override. Provider keys are read from environment variables
(`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`/`GEMINI_API_KEY`,
`XAI_API_KEY`) — pass whichever your model requires.
@@ -318,7 +318,7 @@ Everything the CLI and MCP server can do is also callable from Python.
No subprocess, no extra install — just import and go.
```python
-from synth_panel import quick_poll, run_panel, run_prompt
+from althing import quick_poll, run_panel, run_prompt
# One-shot LLM call
reply = run_prompt("What makes a name feel trustworthy?")
@@ -355,14 +355,14 @@ consume the MCP JSON payload works unchanged.
| `list_panel_results()` / `get_panel_result(id)` | Reload saved results |
Use this path when subprocess overhead hurts (Jupyter, serverless, CI)
-or when you want to wrap SynthPanel in a LangChain / LlamaIndex tool
+or when you want to wrap Althing in a LangChain / LlamaIndex tool
in three lines. See [`examples/sdk_usage.py`](examples/sdk_usage.py)
for a runnable end-to-end walkthrough.
### Typed extraction with Pydantic (1.0.4)
`run_panel` accepts a `pydantic.BaseModel` subclass directly as
-`extract_schema=`. SynthPanel generates the wire JSON Schema via
+`extract_schema=`. Althing generates the wire JSON Schema via
`model_json_schema()` and runs `model_validate` on each panelist's
extracted payload — validation failures surface per-response as
`extraction_validation_error` (the panel still produces a usable result
@@ -371,7 +371,7 @@ constraint, e.g. `rating: 7` against a 1..5 `Likert`).
```python
from pydantic import BaseModel, Field
-from synth_panel import run_panel
+from althing import run_panel
class FeatureChoice(BaseModel):
feature: str = Field(..., min_length=1)
@@ -396,11 +396,11 @@ classes are an additional dispatch, not a replacement.
## MCP Server (Agent Integration)
-synthpanel ships an MCP server so AI agents can run synthetic focus groups as tool calls.
+althing ships an MCP server so AI agents can run synthetic focus groups as tool calls.
```bash
-pip install synthpanel[mcp]
-synthpanel mcp-serve
+pip install althing[mcp]
+althing mcp-serve
```
Add to your editor's MCP config (Claude Code, Cursor, Windsurf):
@@ -408,8 +408,8 @@ Add to your editor's MCP config (Claude Code, Cursor, Windsurf):
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -421,7 +421,7 @@ Add to your editor's MCP config (Claude Code, Cursor, Windsurf):
No API key? No problem. When the invoking MCP client (Claude Desktop,
Claude Code, Cursor, Windsurf) advertises the `sampling` capability,
-synthpanel falls back to asking the client to run the LLM completion on
+althing falls back to asking the client to run the LLM completion on
its behalf — using the client's own subscription. That means `run_prompt`
and small `run_quick_poll` calls (up to 3 personas) work with zero env
setup:
@@ -429,8 +429,8 @@ setup:
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"]
}
}
@@ -469,25 +469,25 @@ One-liner for any supported editor (writes exactly the JSON shown in the
sections below, merging non-destructively into your existing config):
```bash
-synthpanel mcp install --host auto # detect installed editors and confirm each
+althing mcp install --host auto # detect installed editors and confirm each
```
Or pick a host explicitly: `--host claude-code | claude-desktop | cursor |
-windsurf | zed`. `--dry-run` previews the change; `synthpanel mcp uninstall`
+windsurf | zed`. `--dry-run` previews the change; `althing mcp uninstall`
removes exactly the entry it manages. No API key is written unless you pass
-`--env` — set a provider key in your environment or run `synthpanel login`
+`--env` — set a provider key in your environment or run `althing login`
(sampling-capable hosts need no key at all).
Prefer to hand-edit? Copy the JSON snippet for your editor into the listed
-config file, set your API key, and restart the editor. `synthpanel mcp-serve`
+config file, set your API key, and restart the editor. `althing mcp-serve`
is launched on demand over stdio — no long-running process to manage.
Claude Code
```bash
-synthpanel mcp install # ~/.claude.json (all projects)
-synthpanel mcp install --scope project # ./.mcp.json (checked in)
+althing mcp install # ~/.claude.json (all projects)
+althing mcp install --scope project # ./.mcp.json (checked in)
```
Or add to `.mcp.json` at your project root (or `~/.claude.json` for all projects):
@@ -495,8 +495,8 @@ Or add to `.mcp.json` at your project root (or `~/.claude.json` for all projects
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -504,12 +504,12 @@ Or add to `.mcp.json` at your project root (or `~/.claude.json` for all projects
}
```
-Or install the bundled plugin (adds the `/synthpanel-poll `
+Or install the bundled plugin (adds the `/althing-poll `
slash command plus five skills — `focus-group`, `name-test`,
`concept-test`, `survey-prescreen`, `pricing-probe`):
```
-/plugin install synthpanel
+/plugin install althing
```
Not using Claude Code, or prefer manual install? See
@@ -522,8 +522,8 @@ steps and per-host guidance.
Cursor
```bash
-synthpanel mcp install --host cursor # ~/.cursor/mcp.json (all projects)
-synthpanel mcp install --host cursor --scope project # ./.cursor/mcp.json
+althing mcp install --host cursor # ~/.cursor/mcp.json (all projects)
+althing mcp install --host cursor --scope project # ./.cursor/mcp.json
```
Or add to `.cursor/mcp.json` at your project root (or `~/.cursor/mcp.json` for all projects):
@@ -531,8 +531,8 @@ Or add to `.cursor/mcp.json` at your project root (or `~/.cursor/mcp.json` for a
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -546,7 +546,7 @@ Or add to `.cursor/mcp.json` at your project root (or `~/.cursor/mcp.json` for a
Windsurf
```bash
-synthpanel mcp install --host windsurf # ~/.codeium/windsurf/mcp_config.json
+althing mcp install --host windsurf # ~/.codeium/windsurf/mcp_config.json
```
Or add to `~/.codeium/windsurf/mcp_config.json` (or open
@@ -555,8 +555,8 @@ Or add to `~/.codeium/windsurf/mcp_config.json` (or open
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -570,7 +570,7 @@ Or add to `~/.codeium/windsurf/mcp_config.json` (or open
Zed
```bash
-synthpanel mcp install --host zed # ~/.config/zed/settings.json (context_servers schema)
+althing mcp install --host zed # ~/.config/zed/settings.json (context_servers schema)
```
Or hand-edit — Zed uses `context_servers` (not `mcpServers`). Add to `~/.config/zed/settings.json`:
@@ -578,9 +578,9 @@ Or hand-edit — Zed uses `context_servers` (not `mcpServers`). Add to `~/.confi
```json
{
"context_servers": {
- "synth_panel": {
+ "althing": {
"source": "custom",
- "command": "synthpanel",
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -597,8 +597,8 @@ Hermes uses a YAML config with `mcp_servers` and explicit timeout fields. Add th
```yaml
mcp_servers:
- synthpanel:
- command: "synthpanel"
+ althing:
+ command: "althing"
args: ["mcp-serve"]
timeout: 180
connect_timeout: 60
@@ -610,9 +610,9 @@ Or run on demand via `uvx` without a global install:
```yaml
mcp_servers:
- synthpanel:
+ althing:
command: "uvx"
- args: ["--from", "synthpanel[mcp]", "synthpanel", "mcp-serve"]
+ args: ["--from", "althing[mcp]", "althing", "mcp-serve"]
timeout: 180
connect_timeout: 60
env:
@@ -628,7 +628,7 @@ gives the subprocess room to import the MCP SDK on first launch.
Claude Desktop
```bash
-synthpanel mcp install --host claude-desktop # platform-specific config path
+althing mcp install --host claude-desktop # platform-specific config path
```
Or open **Settings → Developer → Edit Config** (or edit the file directly):
@@ -639,8 +639,8 @@ Or open **Settings → Developer → Edit Config** (or edit the file directly):
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -655,9 +655,9 @@ Restart Claude Desktop after editing.
> **Using a non-Anthropic provider?** Swap `ANTHROPIC_API_KEY` for
> `OPENAI_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`, or
> `OPENROUTER_API_KEY` — see [LLM Provider Support](#llm-provider-support).
-> The `synthpanel` binary must be on the editor's `PATH`; if you installed
+> The `althing` binary must be on the editor's `PATH`; if you installed
> into a virtualenv, point `command` at its absolute path
-> (e.g. `/path/to/.venv/bin/synthpanel`).
+> (e.g. `/path/to/.venv/bin/althing`).
## What You Get
@@ -685,7 +685,7 @@ Total: estimated_cost=$0.2360
Each persona responds in character with distinct voice, concerns, and perspective. Cost is tracked and printed per-panelist and in aggregate.
-### Post-hoc Markdown report (`synthpanel report`)
+### Post-hoc Markdown report (`althing report`)
Already have a saved panel result and want a readable share-out? Render
the result to Markdown:
@@ -694,17 +694,17 @@ the result to Markdown:
# Save a run first. --save prints the result ID plus the exact follow-up
# commands (report / results show / results list) so there's no need to
# scrape prose or search the filesystem for the artifact.
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml \
--save
# Render to stdout, either by result ID or path to a result JSON
-synthpanel report
-synthpanel report path/to/result.json
+althing report
+althing report path/to/result.json
# Write to a file
-synthpanel report -o report.md
+althing report -o report.md
```
**Machine-readable handle (agents):** pairing `--save` with
@@ -716,18 +716,18 @@ location. The keys are present **only** when `--save` is active; a checkpointed
run additionally surfaces its checkpoint `run_id`. The human-facing
`Result saved:` hint still goes to stderr, keeping stdout pure JSON.
-#### Discovering saved results (`synthpanel results`)
+#### Discovering saved results (`althing results`)
-`--save` writes to the results store (`~/.synthpanel/results`), which is
-**distinct** from the checkpoint store that `synthpanel runs list` shows.
+`--save` writes to the results store (`~/.althing/results`), which is
+**distinct** from the checkpoint store that `althing runs list` shows.
To rediscover a saved run by its stable ID:
```bash
-synthpanel results list # all saved results, newest first
-synthpanel results show # provenance + canonical saved_path
+althing results list # all saved results, newest first
+althing results show # provenance + canonical saved_path
```
-`results show` prints the recorded provenance (synthpanel/Python version,
+`results show` prints the recorded provenance (althing/Python version,
config hash, pricing snapshot date) and the canonical `saved_path`; in
`--output-format json` it emits the full result envelope plus `saved_path`.
Saved results now embed a `metadata` block, so `report` provenance for
@@ -745,13 +745,13 @@ real-user research:
...
-_Generated by synthpanel report. Synthetic panel — AI-generated responses, not human data._
+_Generated by althing report. Synthetic panel — AI-generated responses, not human data._
```
`report` is scoped to Markdown v1 — provenance, per-model rollup, persona
summary, synthesis, and failure stats. HTML and chart rendering are
deferred to v2. A `report` optional-deps extra exists (`pip install
-synthpanel[report]`) and installs cleanly, but is **currently empty** —
+althing[report]`) and installs cleanly, but is **currently empty** —
it is a forward-compat slot for v2 HTML dependencies and adds nothing
today.
@@ -759,17 +759,17 @@ Full spec: [`specs/sp-viz-layer/`](specs/sp-viz-layer/).
## Packs: Builtin vs Registry
-synthpanel has two kinds of packs, and the distinction matters when you're
+althing has two kinds of packs, and the distinction matters when you're
searching for one:
-- **Builtin packs** ship inside the `synthpanel` wheel. After `pip install
- synthpanel` they are immediately resolvable by name — no `pack import`, no
+- **Builtin packs** ship inside the `althing` wheel. After `pip install
+ althing` they are immediately resolvable by name — no `pack import`, no
network. Reference them anywhere a `--personas` or `--instrument` argument
takes a *name* (the unified resolver also accepts a YAML path).
- **Registry packs** are community-authored. They live in third-party GitHub
repos and are listed in
- [`DataViking-Tech/synthpanel-registry`](https://github.com/DataViking-Tech/synthpanel-registry).
- You pull them with `synthpanel pack import gh:user/repo`; once imported they
+ [`DataViking-Tech/althing-registry`](https://github.com/DataViking-Tech/althing-registry).
+ You pull them with `althing pack import gh:user/repo`; once imported they
become resolvable by name like a builtin. See [docs/registry.md](docs/registry.md)
for URI forms, verification, offline cache, and the submission flow.
@@ -792,7 +792,7 @@ searching for one:
| `startup-founder` | 15 |
| `students` | 15 |
-`synthpanel pack list` (or MCP `list_persona_packs`) enumerates these plus any
+`althing pack list` (or MCP `list_persona_packs`) enumerates these plus any
user-saved packs. Picking the right pack for your task?
See [docs/task-recommendations.md](docs/task-recommendations.md) for the
task → pack → model-config matrix with copy/paste commands.
@@ -803,7 +803,7 @@ task → pack → model-config matrix with copy/paste commands.
`landing-page-comprehension`, `market-research`, `name-test`,
`pricing-discovery`, `product-feedback`.
-`synthpanel instruments list` enumerates these plus any installed packs.
+`althing instruments list` enumerates these plus any installed packs.
If you searched the registry for one of the names above and came up empty,
that's expected — they're SDK builtins, not registry entries. Use the name
@@ -844,7 +844,7 @@ the original. `--personas-merge` is repeatable and appends in order; a
later persona whose `name` matches an earlier one replaces it in place:
```bash
-synthpanel panel run \
+althing panel run \
--personas developer.yaml \
--personas-merge contrarian.yaml \
--personas-merge intern.yaml \
@@ -857,15 +857,15 @@ synthpanel panel run \
You can import persona packs straight from GitHub:
```bash
-# Listed in the synthpanel registry — import by gh: URI
-synthpanel pack import gh:dataviking-tech/example-pack
+# Listed in the althing registry — import by gh: URI
+althing pack import gh:dataviking-tech/example-pack
# Not yet in the registry — opt in explicitly
-synthpanel pack import gh:alice/my-pack --unverified
+althing pack import gh:alice/my-pack --unverified
```
The registry itself is an open, PR-based index at
-[`DataViking-Tech/synthpanel-registry`](https://github.com/DataViking-Tech/synthpanel-registry).
+[`DataViking-Tech/althing-registry`](https://github.com/DataViking-Tech/althing-registry).
See [docs/registry.md](docs/registry.md) for the full reference — supported URL
forms, cache + offline behavior, collision rules, and the flow for publishing
your own pack.
@@ -924,7 +924,7 @@ instrument:
> - **`image` / `screenshot` attachments need a vision-capable model.** Text-only
> models (e.g. `claude-3.5-haiku`) are rejected fast with a clear error — use a
> multimodal model such as `claude-haiku-4.5`, `gpt-4o-mini`, or `gemini-2.0-flash`.
-> - **`fetch_mode: screenshot` requires the visual extra:** `pip install 'synthpanel[visual]'`
+> - **`fetch_mode: screenshot` requires the visual extra:** `pip install 'althing[visual]'`
> (installs Playwright; then `python -m playwright install chromium`). Text modes
> (`markdown` / `html_text`) don't need it.
@@ -940,7 +940,7 @@ loop, no hand-coded conditional flows.
```bash
# The Show HN demo: ~$0.20, one command, the panel decides
# whether to dig into pain, pricing, or alternatives.
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool"
@@ -948,7 +948,7 @@ synthpanel panel run \
`pricing-discovery` is one of eight bundled v3 instrument packs (see
[Builtin instrument packs](#builtin-instrument-packs-8-all-v3-branching)
-above). List them with `synthpanel instruments list`.
+above). List them with `althing instruments list`.
The output now carries a `path` array recording the routing decisions
that actually fired:
@@ -960,7 +960,7 @@ discovery -> probe[themes contains price] -> probe_pricing -> validation
Render the DAG of any instrument:
```bash
-synthpanel instruments graph pricing-discovery --format mermaid
+althing instruments graph pricing-discovery --format mermaid
```
### CLI Flag Support for Multi-Round Runs
@@ -1050,11 +1050,11 @@ also match `pricing`, `priced`, etc.
### `instruments` Subcommand
```bash
-synthpanel instruments list # bundled + installed packs
-synthpanel instruments show pricing-discovery # full YAML body
-synthpanel instruments install ./my-pack.yaml # add a local pack
-synthpanel instruments graph pricing-discovery # text DAG
-synthpanel instruments graph pricing-discovery \
+althing instruments list # bundled + installed packs
+althing instruments show pricing-discovery # full YAML body
+althing instruments install ./my-pack.yaml # add a local pack
+althing instruments graph pricing-discovery # text DAG
+althing instruments graph pricing-discovery \
--format mermaid # mermaid flowchart
```
@@ -1073,7 +1073,7 @@ your own studies.
## LLM Provider Support
-synthpanel works with any LLM provider. Set the appropriate environment variable:
+althing works with any LLM provider. Set the appropriate environment variable:
| Provider | Environment Variable | Model Flag |
|----------|---------------------|------------|
@@ -1086,14 +1086,14 @@ synthpanel works with any LLM provider. Set the appropriate environment variable
```bash
# Use Claude (default)
-synthpanel panel run --personas p.yaml --instrument s.yaml
+althing panel run --personas p.yaml --instrument s.yaml
# Use GPT-4o
-synthpanel panel run --personas p.yaml --instrument s.yaml --model gpt-4o
+althing panel run --personas p.yaml --instrument s.yaml --model gpt-4o
# Use a local model via Ollama
OPENAI_BASE_URL=http://localhost:11434/v1 \
-synthpanel panel run --personas p.yaml --instrument s.yaml --model llama3
+althing panel run --personas p.yaml --instrument s.yaml --model llama3
```
> **Large panels and the OpenRouter default (synthbench#261):** when
@@ -1101,7 +1101,7 @@ synthpanel panel run --personas p.yaml --instrument s.yaml --model llama3
> present — for an OpenRouter-only environment that's `openrouter/auto`,
> whose auto-router can pick a slow reasoning model and stall a
> 20-persona panel for 15+ minutes. So for runs with **≥ 10 personas**
-> and no explicit model, synthpanel auto-selects a fast equivalent
+> and no explicit model, althing auto-selects a fast equivalent
> (`openrouter/anthropic/claude-haiku-4.5`) and prints a one-line note.
> This applies identically on the CLI, SDK, and MCP surfaces. Pass
> `--model openrouter/auto` (or `model="openrouter/auto"`) explicitly to
@@ -1111,24 +1111,24 @@ synthpanel panel run --personas p.yaml --instrument s.yaml --model llama3
### Model Aliases
-synthpanel ships with short aliases (`sonnet`, `opus`, `haiku`, `grok`,
+althing ships with short aliases (`sonnet`, `opus`, `haiku`, `grok`,
`gemini`, `gemini-pro`) that map to canonical model identifiers. You can
override or extend these without changing code:
**Resolution order (highest priority wins):**
-1. **`SYNTHPANEL_MODEL_ALIASES` env var** — JSON string of alias→model pairs
-2. **`~/.synthpanel/aliases.yaml`** — YAML file
+1. **`ALTHING_MODEL_ALIASES` env var** — JSON string of alias→model pairs
+2. **`~/.althing/aliases.yaml`** — YAML file
3. **Hardcoded defaults** — built into the package
```bash
# Override via env var (JSON)
-export SYNTHPANEL_MODEL_ALIASES='{"sonnet": "claude-sonnet-4-6-20250414", "fast": "claude-haiku-4-5-20251001"}'
-synthpanel prompt "Hello" --model fast
+export ALTHING_MODEL_ALIASES='{"sonnet": "claude-sonnet-4-6-20250414", "fast": "claude-haiku-4-5-20251001"}'
+althing prompt "Hello" --model fast
```
```yaml
-# ~/.synthpanel/aliases.yaml
+# ~/.althing/aliases.yaml
aliases:
fast: claude-haiku-4-5-20251001
smart: claude-opus-4-6
@@ -1145,16 +1145,16 @@ want to add or change.
leaderboard and uses the top-ranked model for a topic or dataset:
```bash
-synthpanel panel run --personas p.yaml --instrument s.yaml \
+althing panel run --personas p.yaml --instrument s.yaml \
--best-model-for "Economy & Work"
```
The leaderboard is cached for 24 hours at
-`~/.synthpanel/synthbench-cache.json`. See
+`~/.althing/synthbench-cache.json`. See
[docs/recommended-models.md](docs/recommended-models.md) for the full
rules, offline behaviour, and a use-case → top-model table.
-If the top-ranked entry exposes a display label (e.g. `SynthPanel (Gemini
+If the top-ranked entry exposes a display label (e.g. `Althing (Gemini
Flash Lite)`) rather than a runnable provider model id in its `model`
field, `--best-model-for` substitutes the runnable `model_id` the
leaderboard publishes alongside it (e.g. `google/gemini-2.5-flash-lite`),
@@ -1178,7 +1178,7 @@ cheap models, and a checklist for agents on matching pack to claim strength.
## Architecture
-synthpanel is a research harness, not an LLM wrapper. It orchestrates the research workflow:
+althing is a research harness, not an LLM wrapper. It orchestrates the research workflow:
```
personas.yaml ──┐
@@ -1216,20 +1216,20 @@ instrument.yaml ─┘ ├──> Panelist 2 ──> LLM ──>
```bash
# Human-readable (default)
-synthpanel panel run --personas p.yaml --instrument s.yaml
+althing panel run --personas p.yaml --instrument s.yaml
# JSON (pipe to jq, store in database)
-synthpanel panel run --personas p.yaml --instrument s.yaml --output-format json
+althing panel run --personas p.yaml --instrument s.yaml --output-format json
# NDJSON (streaming, one event per line)
-synthpanel panel run --personas p.yaml --instrument s.yaml --output-format ndjson
+althing panel run --personas p.yaml --instrument s.yaml --output-format ndjson
```
## Budget Control
```bash
# Set a dollar budget for the panel
-synthpanel panel run --personas p.yaml --instrument s.yaml --config budget.yaml
+althing panel run --personas p.yaml --instrument s.yaml --config budget.yaml
```
The cost tracker enforces soft budget limits — the current panelist completes, but no new panelists start if the budget is exceeded.
@@ -1248,7 +1248,7 @@ The `templates/` directory contains four prompt template variants for benchmarki
Usage:
```bash
-synthpanel panel run --personas personas.yaml --instrument survey.yaml --prompt-template templates/demo.txt
+althing panel run --personas personas.yaml --instrument survey.yaml --prompt-template templates/demo.txt
```
Templates use Python format-string syntax (`{field_name}`). Missing persona fields are left as literal `{field_name}` in the output.
@@ -1259,20 +1259,20 @@ Pass `--seed N` to `panel run` for reproducible sampling on providers that
honor the seed parameter (OpenAI, Gemini, xAI, OpenRouter):
```bash
-synthpanel panel run --seed 42 --personas p.yaml --instrument s.yaml
+althing panel run --seed 42 --personas p.yaml --instrument s.yaml
```
-What synthpanel **can** promise:
+What althing **can** promise:
- Forwards the seed to providers that support it.
- Records the seed in the run's `metadata.parameters.seed` and in the
checkpoint fingerprint, so a `--resume` run with a different seed
fails loudly instead of silently mixing samples.
-What synthpanel **cannot** promise:
+What althing **cannot** promise:
- Anthropic's Messages API has no `seed` parameter. When `--seed` is set
- on a Claude model, synthpanel logs a single warning per provider and
+ on a Claude model, althing logs a single warning per provider and
proceeds without determinism. Use `--temperature 0` for closer-to-
deterministic Claude output, but expect drift across model versions.
- Even on supporting providers, "seeded" sampling is best-effort: model
@@ -1280,7 +1280,7 @@ What synthpanel **cannot** promise:
outputs between runs.
`--seed` is for *new* runs you want to be reproducible. To replay a
-previously-cached run exactly, use `synthpanel panel run --resume `
+previously-cached run exactly, use `althing panel run --resume `
— that path serves cached responses verbatim and is independent of
`--seed`. See [docs/reproducibility.md](docs/reproducibility.md) for
the full picture.
@@ -1295,7 +1295,7 @@ Known limitations:
- Cultural and demographic representation has blind spots
- Higher-order correlations between variables are poorly replicated
-Use synthpanel to pre-screen and iterate, then validate with real participants.
+Use althing to pre-screen and iterate, then validate with real participants.
## Multi-Model Ensemble (0.7.0)
@@ -1303,7 +1303,7 @@ Run the same panel through multiple models and blend their response distribution
```bash
# Run 3 models with equal weights and blend distributions
-synthpanel panel run \
+althing panel run \
--models haiku:0.33,gemini:0.33,gpt-4o-mini:0.34 \
--blend \
--personas personas.yaml \
@@ -1318,10 +1318,10 @@ The blended output includes per-model distributions and the weighted ensemble di
## Running at Scale
-For panels of 500 to 10,000+ panelists, synthpanel can track response-distribution convergence live via Jensen-Shannon divergence and optionally auto-stop once every bounded (Likert / yes-no / pick-one / enum) question has stabilized. The post-run JSON gains a top-level `convergence` section showing the smallest `n` at which each question converged, so you can confidently run smaller next time.
+For panels of 500 to 10,000+ panelists, althing can track response-distribution convergence live via Jensen-Shannon divergence and optionally auto-stop once every bounded (Likert / yes-no / pick-one / enum) question has stabilized. The post-run JSON gains a top-level `convergence` section showing the smallest `n` at which each question converged, so you can confidently run smaller next time.
```bash
-synthpanel panel run \
+althing panel run \
--personas large-panel.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
@@ -1336,7 +1336,7 @@ jq '.convergence.overall_converged_at, .convergence.auto_stopped' result.json
See [docs/convergence.md](docs/convergence.md) for methodology, tuning, and the
optional `--convergence-baseline` flag that compares your run against a real-human
-baseline from [SynthBench](https://github.com/DataViking-Tech/synthbench) (install via `pip install 'synthpanel[convergence]'`).
+baseline from [SynthBench](https://github.com/DataViking-Tech/synthbench) (install via `pip install 'althing[convergence]'`).
### Submitting calibrated runs to SynthBench
@@ -1348,7 +1348,7 @@ completes:
```bash
export SYNTHBENCH_API_KEY=sk_synthbench_... # mint at synthbench.org/account
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument happiness-probe \
--calibrate-against gss:HAPPY \
@@ -1357,7 +1357,7 @@ synthpanel panel run \
```
First use shows a one-screen privacy notice (recorded at
-`~/.synthpanel/synthbench-consent.json` so subsequent runs don't re-prompt;
+`~/.althing/synthbench-consent.json` so subsequent runs don't re-prompt;
pass `--yes` for CI). Submission failures are warned-but-non-fatal so a
slow SynthBench cannot fail your panel run. See
[docs/synthbench-integration.md](docs/synthbench-integration.md) for the
@@ -1368,22 +1368,22 @@ modes.
| Version | Highlights |
|---------|-----------|
-| 1.5.x *(current)* | `synthpanel mcp install --host auto` one-liner host registration; four canonical persona packs; deterministic `poll-summary` rollups; MCP auto-picks a fast model for ≥10-persona panels; `results list`/`results show` for the saved-results store; `python -m synthpanel` alias; fail-loud empty attachments and typed `response_schema` enforcement; synthesis routing follows the panel's provider; PyPI Trusted Publishing + auto-tag version-drift guard |
+| 1.5.x *(current)* | `althing mcp install --host auto` one-liner host registration; four canonical persona packs; deterministic `poll-summary` rollups; MCP auto-picks a fast model for ≥10-persona panels; `results list`/`results show` for the saved-results store; `python -m althing` alias; fail-loud empty attachments and typed `response_schema` enforcement; synthesis routing follows the panel's provider; PyPI Trusted Publishing + auto-tag version-drift guard |
| 1.4.0 | Explicit `cost_estimated_usd` / `cost_actual_usd` (+ `per_model_breakdown`) on `EnsembleResult`, `ModelRunResult`, and `SynthesisResult` — estimate-vs-bill reconciliation without inspecting raw usage |
-| 1.3.0 | `trafilatura` moved to the `[full]` extra so bare `pip install synthpanel` works on pyodide/Cloudflare Python Workers (no `lxml` C extension required) |
-| 1.2.0 | Pyodide-safe / async-DI surface for `synth_panel.ensemble.synthesize_panel` — drive the judge call through your own async LLM client |
-| 1.1.0 | `synth_panel.ensemble` frozen as the supported public API for the ensemble/deliberation core |
+| 1.3.0 | `trafilatura` moved to the `[full]` extra so bare `pip install althing` works on pyodide/Cloudflare Python Workers (no `lxml` C extension required) |
+| 1.2.0 | Pyodide-safe / async-DI surface for `althing.ensemble.synthesize_panel` — drive the judge call through your own async LLM client |
+| 1.1.0 | `althing.ensemble` frozen as the supported public API for the ensemble/deliberation core |
| 1.0.6 | Cross-town dogfood friction sweep on the v1.0.x line; `panel_verdict` emitted on the MCP success path; release-dogfood protocol codified |
| 1.0.0 | Frozen MCP contract (`schemas/v1.0.0.json`, `schema_version` echoed on every response and typed error); multimodal attachments (images, URLs, PDFs, inline HTML) with stratified delivery and a URL-fetch security perimeter |
-| 0.12.0 | `--best-model-for TOPIC[:DATASET]` SynthBench-driven model picker, `--submit-to-synthbench`, `synthpanel pack calibrate`, six bundled packs deepened 5 → 15 personas |
+| 0.12.0 | `--best-model-for TOPIC[:DATASET]` SynthBench-driven model picker, `--submit-to-synthbench`, `althing pack calibrate`, six bundled packs deepened 5 → 15 personas |
| 0.11.0 | `sp-i2ub` scaled-orchestration epic: panelist-level checkpointing with `--resume ` and auto-checkpoint on SIGINT/SIGTERM (every K=25 panelists), `--max-cost ` mid-run projected-total cost gate that halts gracefully with valid partial JSON, and valid-partial-JSON discipline on every abort path (rate-exhaustion, SIGINT, cost-gate, panelist failure) with `run_invalid: true` + specific `abort_reason` and exit code 2; 6-bug loudness sweep turning silent failures loud across alias parse, synthesis partial payload, MCP `extend_panel`, condition evaluator, orchestrator follow-up exceptions, and the `test_aliases` fixture; auto-tag now fails loudly on unlabeled release PRs; `pip-audit` ignores CVE-2026-3219 in pip 26.0.1 |
-| 0.10.0 | `synthpanel report` post-hoc Markdown renderer for saved panel results (behind `[report]` extra); inline SynthBench calibration via `panel run --calibrate-against DATASET:QUESTION` with auto-derived `pick_one` schema and `per_question[key].calibration` sub-object wire format; decentralized pack registry — `pack import gh:/` with `--unverified`, `pack search`, `pack list --registry`, 24h cache + offline fallback; optional `version:` field on persona packs with opt-in shadow warning |
-| 0.9.9 | `--synthesis-strategy=auto` now routes to map-reduce on context overflow instead of hard-failing; OpenRouter alias resolution tightened for sub-1¢ local-table sanity checks; `--personas-merge` warns (or errors via `--personas-merge-on-collision`) on name collisions with bundled packs; version single-sourced from `src/synth_panel/__version__.py` with templated site render |
-| 0.9.8 | Fail-loud synthesis (context-overflow pre-flight + structured `synthesis_error`), per-question map-reduce synthesis (`--synthesis-strategy=single\|map-reduce\|auto`), response-schema validation with deterministic distributions for bounded question types, rate-limit-aware client (`--max-concurrent`, `--rate-limit-rps`), live convergence telemetry + `--auto-stop`, 4 new bundled persona packs (`job-seekers`, `recruiters-talent`, `product-research`, `ai-eval-buyers`) raising shipped personas 24 → 84, `/synthpanel-poll` slash command |
+| 0.10.0 | `althing report` post-hoc Markdown renderer for saved panel results (behind `[report]` extra); inline SynthBench calibration via `panel run --calibrate-against DATASET:QUESTION` with auto-derived `pick_one` schema and `per_question[key].calibration` sub-object wire format; decentralized pack registry — `pack import gh:/` with `--unverified`, `pack search`, `pack list --registry`, 24h cache + offline fallback; optional `version:` field on persona packs with opt-in shadow warning |
+| 0.9.9 | `--synthesis-strategy=auto` now routes to map-reduce on context overflow instead of hard-failing; OpenRouter alias resolution tightened for sub-1¢ local-table sanity checks; `--personas-merge` warns (or errors via `--personas-merge-on-collision`) on name collisions with bundled packs; version single-sourced from `src/althing/__version__.py` with templated site render |
+| 0.9.8 | Fail-loud synthesis (context-overflow pre-flight + structured `synthesis_error`), per-question map-reduce synthesis (`--synthesis-strategy=single\|map-reduce\|auto`), response-schema validation with deterministic distributions for bounded question types, rate-limit-aware client (`--max-concurrent`, `--rate-limit-rps`), live convergence telemetry + `--auto-stop`, 4 new bundled persona packs (`job-seekers`, `recruiters-talent`, `product-research`, `ai-eval-buyers`) raising shipped personas 24 → 84, `/althing-poll` slash command |
| 0.9.7 | Provider-reported cost is authoritative — when a provider returns `usage.cost` (e.g. OpenRouter), that value is recorded verbatim instead of being recomputed from a local pricing table; `pricing_fallback` warning surfaced when a model falls through to `DEFAULT_PRICING`; ensemble rounding no longer silently drops low-weight models |
| 0.9.5 | Fail-fast on unsubstituted `{placeholder}` variables in instruments/personas, `--personas-merge PATH` for layered persona packs, `--dry-run` pre-run preview, `run_invalid` flag on degenerate runs, MCP BYOK detection routes through the credentials store |
-| 0.9.4 | `synthpanel login` / `logout` / `whoami` credential-store CLI; MCP recognises `OPENROUTER_API_KEY` as BYOK and picks a sensible default; Docker images on GHCR + Docker Hub multi-arch; MCP sampling fallback for `run_prompt` and `run_quick_poll` |
-| 0.9.0 | First release post-public-flip. Repo renamed to `SynthPanel` (PyPI name `synthpanel` unchanged) |
+| 0.9.4 | `althing login` / `logout` / `whoami` credential-store CLI; MCP recognises `OPENROUTER_API_KEY` as BYOK and picks a sensible default; Docker images on GHCR + Docker Hub multi-arch; MCP sampling fallback for `run_prompt` and `run_quick_poll` |
+| 0.9.0 | First release post-public-flip. Repo renamed to `Althing` (PyPI name `althing` unchanged) |
| 0.8.0 | `lookup_pricing_by_provider` public helper for synthbench-format provider strings; multi-question CLI cost shape symmetry (`total_cost` / `panelist_cost` / `total_usage` / `panelist_usage`) |
| 0.7.0 | Multi-model ensemble blending (`--blend`), OpenRouter provider support, temperature/top_p controls, prompt template customization |
| 0.6.0 | `--models` weighted model spec, `--temperature`/`--top_p` flags, persona prompt templates, pack generation, domain templates, MCP improvements |
@@ -1399,7 +1399,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and how t
## Benchmarked on SynthBench
-synthpanel's ability to produce representative synthetic respondents is measured by [SynthBench](https://synthbench.org), an open benchmark for synthetic survey quality (a sibling DataViking project, operated by the SynthPanel maintainers).
+althing's ability to produce representative synthetic respondents is measured by [SynthBench](https://synthbench.org), an open benchmark for synthetic survey quality (a sibling DataViking project, operated by the Althing maintainers).
- **Want proof it works?** Browse the [leaderboard](https://synthbench.org) — the 3-model ensemble blend scores SPS 0.877 on opinionsqa, 0.858 on subpop, and 0.813 on globalopinionqa (leaderboard generated 2026-07-17; numbers move as the board recomputes).
- **Got a great configuration?** [Submit your scores](https://synthbench.org) and compare against baselines.
diff --git a/SECURITY.md b/SECURITY.md
index b42abc17..ef6b0481 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,7 +2,7 @@
## Reporting a Vulnerability
-If you discover a security vulnerability in SynthPanel, please report it responsibly.
+If you discover a security vulnerability in Althing, please report it responsibly.
**Do not open a public GitHub issue for security vulnerabilities.**
diff --git a/SPEC.md b/SPEC.md
index 10baa5f2..afd71447 100644
--- a/SPEC.md
+++ b/SPEC.md
@@ -2,9 +2,9 @@
**Version**: 1.0.0
**Date**: 2026-04-03
-**Purpose**: Functional specification for a synthetic focus group CLI tool ("synthpanel") that orchestrates multiple LLM-powered personas to generate structured qualitative feedback.
+**Purpose**: Functional specification for a synthetic focus group CLI tool ("althing") that orchestrates multiple LLM-powered personas to generate structured qualitative feedback.
-**Audience**: Implementers who will build synthpanel from scratch. This document describes behavioral contracts and data flows only -- no implementation details from any reference codebase.
+**Audience**: Implementers who will build althing from scratch. This document describes behavioral contracts and data flows only -- no implementation details from any reference codebase.
---
@@ -231,7 +231,7 @@ A single turn proceeds as follows:
### Purpose
-Manage the lifecycle of multiple independent agent sessions working in parallel or in a coordinated workflow. For synthpanel, this means spawning one agent per panelist persona and coordinating their execution.
+Manage the lifecycle of multiple independent agent sessions working in parallel or in a coordinated workflow. For althing, this means spawning one agent per panelist persona and coordinating their execution.
### Interface Contract
@@ -307,7 +307,7 @@ Spawning --> ReadyForPrompt --> PromptAccepted --> Running --> Finished
### Extension Points
- Detection heuristics (trust prompts, ready cues, running cues, shell prompts) are configurable pattern lists.
-- The registry is an in-memory data structure. For synthpanel, this is sufficient -- persistent orchestration state is handled by the session persistence layer.
+- The registry is an in-memory data structure. For althing, this is sufficient -- persistent orchestration state is handled by the session persistence layer.
---
@@ -344,7 +344,7 @@ The structured output system provides:
### Behavioral Requirements
-For synthpanel, the primary pattern is:
+For althing, the primary pattern is:
1. Define a "respond" tool whose input schema matches the desired panelist response format.
2. Set tool_choice to "specific" with the respond tool's name.
@@ -540,7 +540,7 @@ Provide the command-line interface through which operators configure and run foc
- `prompt `: Run a single non-interactive prompt and exit. All remaining arguments are joined as the prompt text.
- `login`: Start an authentication flow (e.g., OAuth).
- `logout`: Clear saved authentication credentials.
-- (Additional subcommands as needed for synthpanel: `panel run`, `panel resume`, etc.)
+- (Additional subcommands as needed for althing: `panel run`, `panel resume`, etc.)
**Interactive Mode** (when no subcommand is given):
- Enter a REPL loop.
@@ -718,7 +718,7 @@ All registries (worker, team, cron) use interior mutability with mutex guards. T
### Naming Conventions for Synth-Panel
-When implementing these foundations for synthpanel, use domain-appropriate names:
+When implementing these foundations for althing, use domain-appropriate names:
| Foundation Concept | Synth-Panel Term |
|-------------------|-----------------|
@@ -733,7 +733,7 @@ When implementing these foundations for synthpanel, use domain-appropriate names
### Minimum Viable Subset
-For a first working version of synthpanel, the following components are required in this order:
+For a first working version of althing, the following components are required in this order:
1. **LLM Client Abstraction** -- needed for everything
2. **Structured Output** -- panelist responses must be schema-conformant
@@ -778,15 +778,15 @@ Each component must be validated against a live LLM API (Claude or OpenAI-compat
- Verify auto-compaction triggers after exceeding the token threshold (can be set low for testing, e.g., 1000 tokens).
### CLI Framework
-- `synthpanel prompt "Say hello"` exits 0 and prints a response.
-- `synthpanel prompt "Say hello" --output-format json` outputs valid JSON with message and usage fields.
-- `synthpanel --help` prints usage information.
+- `althing prompt "Say hello"` exits 0 and prints a response.
+- `althing prompt "Say hello" --output-format json` outputs valid JSON with message and usage fields.
+- `althing --help` prints usage information.
- Invalid subcommand exits non-zero with an error message.
### Integration (end-to-end)
- Define 3 personas in YAML (e.g., "skeptical CTO", "enthusiastic intern", "pragmatic PM").
- Define a survey instrument asking "What do you think of the name 'Traitprint' for a career matching app?"
-- Run `synthpanel run --personas personas.yaml --instrument survey.yaml --model sonnet`.
+- Run `althing run --personas personas.yaml --instrument survey.yaml --model sonnet`.
- Verify: 3 structured responses returned, each conforming to the schema, each with different content reflecting the persona, total cost printed.
---
@@ -794,7 +794,7 @@ Each component must be validated against a live LLM API (Claude or OpenAI-compat
## 12. v1.0.0 Frozen MCP Response Contract
**v1.0.0 boundary — frozen at this point.** The schema below ships as
-`synthpanel/schemas/v1.0.0.json`, embedded in the package. `schema_version`
+`althing/schemas/v1.0.0.json`, embedded in the package. `schema_version`
is echoed in every response and every error. Breaking changes = major bump +
parallel schema file (no in-place mutation). An append-only-schema CI linter
gates this.
@@ -958,7 +958,7 @@ re-validation (catastrophic case).
#### Default behavior
-`SYNTHPANEL_DRIFT_DEGRADE` env flag: **off by default in v1.0.0** (typed
+`ALTHING_DRIFT_DEGRADE` env flag: **off by default in v1.0.0** (typed
error on exhaustion), **on by default in v1.1.0** (degraded artifact with
flag). Documented in `docs/mcp.md` host-integration section. Migration note
in v1.1 CHANGELOG.
@@ -977,7 +977,7 @@ Justification: fail fast, fail closed.
#### Schema asset
-Single file: `synthpanel/schemas/v1.0.0.json`, embedded in the package. No
+Single file: `althing/schemas/v1.0.0.json`, embedded in the package. No
remote URL — offline-safe, deterministic, no DNS dependency. Published URL
is a v2 problem.
diff --git a/commands/synthpanel-poll.md b/commands/althing-poll.md
similarity index 85%
rename from commands/synthpanel-poll.md
rename to commands/althing-poll.md
index 0da9abf0..71598f8a 100644
--- a/commands/synthpanel-poll.md
+++ b/commands/althing-poll.md
@@ -1,13 +1,13 @@
---
description: Run a one-question synthetic poll across AI personas and synthesize the themes
allowed-tools:
- - mcp__synth_panel__run_quick_poll
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__get_persona_pack
+ - mcp__althing__run_quick_poll
+ - mcp__althing__list_persona_packs
+ - mcp__althing__get_persona_pack
argument-hint:
---
-Run a quick synthetic poll using the SynthPanel MCP server. One question, a
+Run a quick synthetic poll using the Althing MCP server. One question, a
handful of AI personas, one synthesized writeup.
Question: $ARGUMENTS
@@ -21,7 +21,7 @@ Question: $ARGUMENTS
omitting the `personas` argument. Only build a custom list when the user
names a specific audience (e.g. "three enterprise SRE personas"). In that
case, either:
- - Call `mcp__synth_panel__list_persona_packs` and `get_persona_pack` to
+ - Call `mcp__althing__list_persona_packs` and `get_persona_pack` to
pull an installed pack, or
- Hand-author 3–5 dicts with `name`, `age`, `occupation`, `background`,
and `personality_traits`.
@@ -29,7 +29,7 @@ Question: $ARGUMENTS
Keep panels small — `run_quick_poll` caps at 3 personas when running in
sampling mode (no API key).
-3. **Run the poll.** Call `mcp__synth_panel__run_quick_poll` with:
+3. **Run the poll.** Call `mcp__althing__run_quick_poll` with:
- `question`: the user's question
- `personas`: omit for the default set, or pass your custom list
- `synthesis`: leave as `true` (default) — the synthesis pass is the
@@ -67,7 +67,7 @@ Question: $ARGUMENTS
a single-line caveat: "Synthetic panel — directional signal only, not a
substitute for real user research."
- **Don't loop.** If the user wants a second question, that's another
- `/synthpanel-poll` invocation, not a follow-up inside this one. For
+ `/althing-poll` invocation, not a follow-up inside this one. For
multi-question structured studies, suggest the `/focus-group` skill
instead.
- **Report errors honestly.** If the tool returns an `error` field
diff --git a/docs/RELEASING.md b/docs/RELEASING.md
index 2a7bda8b..f98b4c77 100644
--- a/docs/RELEASING.md
+++ b/docs/RELEASING.md
@@ -1,4 +1,4 @@
-# Releasing synthpanel
+# Releasing althing
## Release flow (production PyPI)
@@ -15,7 +15,7 @@ Releases follow semver and are fully automated via GitHub Actions:
- Computes the next version from the latest `v*.*.*` tag.
- Creates and pushes a new git tag (e.g. `v0.5.0`).
- Creates a GitHub Release with auto-generated notes.
- - Triggers `publish.yml` which builds and publishes to [PyPI](https://pypi.org/project/synthpanel/).
+ - Triggers `publish.yml` which builds and publishes to [PyPI](https://pypi.org/project/althing/).
### Manual publish
@@ -28,7 +28,7 @@ You can re-publish an existing tag via workflow dispatch:
A v1.5.3 dogfood found the public surfaces disagreeing about the current
version (PyPI said `1.5.3`, GitHub `releases/latest` said `v1.0.3`,
-synthpanel.dev said `v1.4.0`). `auto-tag.yml` now creates the GitHub Release
+althing.dev said `v1.4.0`). `auto-tag.yml` now creates the GitHub Release
and syncs every version artifact on each bump, but **verify all four surfaces
after every release** so a silent gap can't reopen (issue #524):
@@ -36,19 +36,19 @@ after every release** so a silent gap can't reopen (issue #524):
VER="1.5.3" # the version you just released
# 1. PyPI — the canonical artifact.
-curl -s https://pypi.org/pypi/synthpanel/json | jq -r '.info.version' # → $VER
+curl -s https://pypi.org/pypi/althing/json | jq -r '.info.version' # → $VER
# 2. GitHub releases/latest — must equal the PyPI version.
-gh api repos/DataViking-Tech/SynthPanel/releases/latest --jq '.tag_name' # → v$VER
+gh api repos/DataViking-Tech/Althing/releases/latest --jq '.tag_name' # → v$VER
# 3. Tags vs releases — every release tag should have a Release (no gap).
comm -23 \
<(git tag --list 'v1.*' --sort=v:refname) \
- <(gh release list -R DataViking-Tech/SynthPanel -L 100 --json tagName --jq '.[].tagName' | sort -V)
+ <(gh release list -R DataViking-Tech/Althing -L 100 --json tagName --jq '.[].tagName' | sort -V)
# (empty output = aligned)
-# 4. synthpanel.dev — the live landing hero must show the new version.
-curl -s https://synthpanel.dev/ | grep -o 'v[0-9.]* — public beta' # → v$VER — public beta
+# 4. althing.dev — the live landing hero must show the new version.
+curl -s https://althing.dev/ | grep -o 'v[0-9.]* — public beta' # → v$VER — public beta
```
If `releases/latest` lags PyPI (e.g. older tags were cut before the GitHub
@@ -56,21 +56,21 @@ Release step existed), backfill the missing releases — mark only the newest as
latest:
```bash
-gh release create vX.Y.Z -R DataViking-Tech/SynthPanel \
+gh release create vX.Y.Z -R DataViking-Tech/Althing \
--verify-tag --generate-notes --title "vX.Y.Z" --latest=false # backfilled intermediate
-gh release create vNEWEST -R DataViking-Tech/SynthPanel \
+gh release create vNEWEST -R DataViking-Tech/Althing \
--verify-tag --generate-notes --title "vNEWEST" --latest # current latest
```
> **Social card.** `site/og-image.png` / `site/github-social-preview.png`
> embed the version too. `site/generate-og-image.py` reads it from
-> `src/synth_panel/__version__.py` (no longer hardcoded); rerun
+> `src/althing/__version__.py` (no longer hardcoded); rerun
> `python3 site/generate-og-image.py` and commit the PNGs if the card text
> drifts from the released version.
## Dev builds (TestPyPI)
-Every merge to `main` automatically publishes a dev build to [TestPyPI](https://test.pypi.org/project/synthpanel/):
+Every merge to `main` automatically publishes a dev build to [TestPyPI](https://test.pypi.org/project/althing/):
- Version format: `{base_version}.dev{run_number}` (e.g. `0.4.0.dev42`).
- Workflow: `publish-test.yml`.
@@ -80,29 +80,29 @@ Every merge to `main` automatically publishes a dev build to [TestPyPI](https://
```bash
# Latest dev build from TestPyPI
-pip install -i https://test.pypi.org/simple/ synthpanel
+pip install -i https://test.pypi.org/simple/ althing
# Specific dev version
-pip install -i https://test.pypi.org/simple/ synthpanel==0.4.0.dev42
+pip install -i https://test.pypi.org/simple/ althing==0.4.0.dev42
```
> **Note:** TestPyPI may not have all dependencies. If installation fails due to
-> missing deps, install them from real PyPI first, then install synthpanel from
+> missing deps, install them from real PyPI first, then install althing from
> TestPyPI:
>
> ```bash
> pip install httpx pyyaml
-> pip install -i https://test.pypi.org/simple/ --no-deps synthpanel==0.4.0.dev42
+> pip install -i https://test.pypi.org/simple/ --no-deps althing==0.4.0.dev42
> ```
## Install a release
```bash
# Latest stable release from PyPI
-pip install synthpanel
+pip install althing
# Specific version
-pip install synthpanel==0.4.0
+pip install althing==0.4.0
```
## GitHub environments
diff --git a/docs/adapter-guide.md b/docs/adapter-guide.md
index fd453f9f..10b26b6d 100644
--- a/docs/adapter-guide.md
+++ b/docs/adapter-guide.md
@@ -1,6 +1,6 @@
-# Writing a synthpanel LLM Adapter
+# Writing a althing LLM Adapter
-This guide walks through adding support for a new LLM provider to synthpanel by writing an **adapter** — a thin translator between synthpanel's internal request/response model and a provider's HTTP API. It is the highest-leverage way to contribute: one adapter makes every synthpanel feature (panels, MCP tools, ensemble blending, budgeting, branching) instantly available against a new backend.
+This guide walks through adding support for a new LLM provider to althing by writing an **adapter** — a thin translator between althing's internal request/response model and a provider's HTTP API. It is the highest-leverage way to contribute: one adapter makes every althing feature (panels, MCP tools, ensemble blending, budgeting, branching) instantly available against a new backend.
The canonical behavioral contract is [SPEC.md §2 — LLM Client Abstraction](../SPEC.md). This guide is the hands-on companion: what files to touch, what `LLMProvider` looks like in code, and a complete worked example (a hypothetical Mistral adapter).
@@ -10,20 +10,20 @@ The canonical behavioral contract is [SPEC.md §2 — LLM Client Abstraction](..
### What is an adapter?
-An adapter is a Python module in `src/synth_panel/llm/providers/` that:
+An adapter is a Python module in `src/althing/llm/providers/` that:
- Subclasses `LLMProvider` (from `base.py`)
- Implements two methods: `send()` (blocking) and `stream()` (iterator of SSE events)
- Declares a `ProviderConfig` describing its env vars, base URL, and model prefixes
- Gets registered in the provider resolver (`client.py`) so model strings like `"mistral-large-latest"` route to it automatically
-The rest of synthpanel — orchestrator, cost tracker, MCP server, CLI — never talks to the provider directly. It only holds an `LLMClient`, which picks the right adapter by inspecting the model identifier and the environment.
+The rest of althing — orchestrator, cost tracker, MCP server, CLI — never talks to the provider directly. It only holds an `LLMClient`, which picks the right adapter by inspecting the model identifier and the environment.
### When would you write one?
Write a new adapter when:
-- The provider exposes its own API shape (Anthropic-style, Gemini-style) that isn't OpenAI-compatible. Adapters like `anthropic.py` and `gemini.py` translate native formats into synthpanel's internal model.
+- The provider exposes its own API shape (Anthropic-style, Gemini-style) that isn't OpenAI-compatible. Adapters like `anthropic.py` and `gemini.py` translate native formats into althing's internal model.
- The provider is OpenAI-compatible but warrants a first-class entry — a dedicated env var, prefix-based routing, a specific default base URL. OpenRouter and xAI both follow this pattern: they reuse `_openai_format.py` helpers but live as their own module for discoverability and config isolation.
- The provider needs adapter-specific behavior (auth refresh, response translation quirks, custom streaming framing) that shouldn't pollute the generic `openai_compat` provider.
@@ -31,18 +31,18 @@ If the provider is plain-vanilla OpenAI-compatible and doesn't need a dedicated
## 2. The LLMProvider base class
-Source: [`src/synth_panel/llm/providers/base.py`](../src/synth_panel/llm/providers/base.py)
+Source: [`src/althing/llm/providers/base.py`](../src/althing/llm/providers/base.py)
Every adapter implements this interface:
```python
from collections.abc import Iterator
-from synth_panel.llm.models import (
+from althing.llm.models import (
CompletionRequest,
CompletionResponse,
StreamEvent,
)
-from synth_panel.llm.providers.base import LLMProvider, ProviderConfig
+from althing.llm.providers.base import LLMProvider, ProviderConfig
class MyProvider(LLMProvider):
@@ -77,7 +77,7 @@ Three helpers come for free:
### Data models
-`CompletionRequest`, `CompletionResponse`, `StreamEvent`, `TokenUsage`, and content block types live in [`src/synth_panel/llm/models.py`](../src/synth_panel/llm/models.py). They are provider-agnostic — your job is to translate to and from the provider's wire format.
+`CompletionRequest`, `CompletionResponse`, `StreamEvent`, `TokenUsage`, and content block types live in [`src/althing/llm/models.py`](../src/althing/llm/models.py). They are provider-agnostic — your job is to translate to and from the provider's wire format.
The four token buckets (`input_tokens`, `output_tokens`, `cache_write_tokens`, `cache_read_tokens`) feed the cost tracker. If the provider doesn't expose cache counters, leave them at `0`.
@@ -87,7 +87,7 @@ A hypothetical worked example. Mistral exposes an OpenAI-compatible chat complet
### Step 1 — Create the module
-`src/synth_panel/llm/providers/mistral.py`:
+`src/althing/llm/providers/mistral.py`:
```python
"""Mistral provider (OpenAI-compatible chat completions).
@@ -102,14 +102,14 @@ from collections.abc import Iterator
import httpx
-from synth_panel.llm.errors import LLMError, LLMErrorCategory, classify_http_status
-from synth_panel.llm.models import CompletionRequest, CompletionResponse, StreamEvent
-from synth_panel.llm.providers._openai_format import (
+from althing.llm.errors import LLMError, LLMErrorCategory, classify_http_status
+from althing.llm.models import CompletionRequest, CompletionResponse, StreamEvent
+from althing.llm.providers._openai_format import (
build_openai_body,
parse_openai_response,
parse_openai_sse_stream,
)
-from synth_panel.llm.providers.base import LLMProvider, ProviderConfig
+from althing.llm.providers.base import LLMProvider, ProviderConfig
MISTRAL_CONFIG = ProviderConfig(
api_key_env="MISTRAL_API_KEY",
@@ -215,10 +215,10 @@ If the provider uses Anthropic-style events instead of OpenAI SSE, you'll need a
### Step 4 — Register in the provider resolver
-`src/synth_panel/llm/client.py`:
+`src/althing/llm/client.py`:
```python
-from synth_panel.llm.providers.mistral import MISTRAL_CONFIG, MistralProvider
+from althing.llm.providers.mistral import MISTRAL_CONFIG, MistralProvider
_PROVIDER_REGISTRY: list[tuple[ProviderConfig, type[LLMProvider]]] = [
(ANTHROPIC_CONFIG, AnthropicProvider),
@@ -236,7 +236,7 @@ Also update the "no credentials" error message at the bottom of `_resolve_provid
### Step 5 — Env var convention
-synthpanel follows a two-variable convention per provider:
+althing follows a two-variable convention per provider:
| Variable | Purpose |
|----------|---------|
@@ -245,7 +245,7 @@ synthpanel follows a two-variable convention per provider:
For Mistral: `MISTRAL_API_KEY` and `MISTRAL_BASE_URL`. Keep the naming consistent — users, CI configs, and the MCP server env block all rely on the `_API_KEY` pattern.
-If your provider supports an alias (e.g. `SYNTHPANEL_MODEL_ALIASES='{"mistral-small": "mistral-small-latest"}'`), document it but do not hardcode new aliases in `aliases.py` unless the short name is already well-known across the ecosystem (as `haiku`, `sonnet`, `gemini` are).
+If your provider supports an alias (e.g. `ALTHING_MODEL_ALIASES='{"mistral-small": "mistral-small-latest"}'`), document it but do not hardcode new aliases in `aliases.py` unless the short name is already well-known across the ecosystem (as `haiku`, `sonnet`, `gemini` are).
### Step 6 — Unit tests
@@ -266,8 +266,8 @@ from unittest.mock import MagicMock, patch
import httpx
import pytest
-from synth_panel.llm.errors import LLMError, LLMErrorCategory
-from synth_panel.llm.models import CompletionRequest, InputMessage, TextBlock
+from althing.llm.errors import LLMError, LLMErrorCategory
+from althing.llm.models import CompletionRequest, InputMessage, TextBlock
def _request(model: str = "mistral-large-latest") -> CompletionRequest:
@@ -303,7 +303,7 @@ def _mock_http(data: dict, status_code: int = 200) -> MagicMock:
class TestMistralProviderSend:
def test_happy_path(self, monkeypatch):
monkeypatch.setenv("MISTRAL_API_KEY", "test-key")
- from synth_panel.llm.providers.mistral import MistralProvider
+ from althing.llm.providers.mistral import MistralProvider
provider = MistralProvider()
with patch("httpx.post", return_value=_mock_http(_ok_response())):
@@ -315,7 +315,7 @@ class TestMistralProviderSend:
def test_missing_api_key(self, monkeypatch):
monkeypatch.delenv("MISTRAL_API_KEY", raising=False)
- from synth_panel.llm.providers.mistral import MistralProvider
+ from althing.llm.providers.mistral import MistralProvider
with pytest.raises(LLMError) as exc_info:
MistralProvider()
@@ -323,7 +323,7 @@ class TestMistralProviderSend:
def test_rate_limit_is_retryable(self, monkeypatch):
monkeypatch.setenv("MISTRAL_API_KEY", "test-key")
- from synth_panel.llm.providers.mistral import MistralProvider
+ from althing.llm.providers.mistral import MistralProvider
provider = MistralProvider()
with patch("httpx.post", return_value=_mock_http({}, status_code=429)):
@@ -333,7 +333,7 @@ class TestMistralProviderSend:
def test_bad_request_is_not_retryable(self, monkeypatch):
monkeypatch.setenv("MISTRAL_API_KEY", "test-key")
- from synth_panel.llm.providers.mistral import MistralProvider
+ from althing.llm.providers.mistral import MistralProvider
provider = MistralProvider()
with patch("httpx.post", return_value=_mock_http({}, status_code=400)):
@@ -343,7 +343,7 @@ class TestMistralProviderSend:
def test_transport_error_raises_transport_category(self, monkeypatch):
monkeypatch.setenv("MISTRAL_API_KEY", "test-key")
- from synth_panel.llm.providers.mistral import MistralProvider
+ from althing.llm.providers.mistral import MistralProvider
provider = MistralProvider()
with patch("httpx.post", side_effect=httpx.ConnectError("boom")):
@@ -354,7 +354,7 @@ class TestMistralProviderSend:
def test_base_url_override(self, monkeypatch):
monkeypatch.setenv("MISTRAL_API_KEY", "test-key")
monkeypatch.setenv("MISTRAL_BASE_URL", "https://proxy.example.com")
- from synth_panel.llm.providers.mistral import MistralProvider
+ from althing.llm.providers.mistral import MistralProvider
provider = MistralProvider()
assert provider._base_url == "https://proxy.example.com"
@@ -388,7 +388,7 @@ The acceptance marker is load-bearing: [`tests/conftest.py`](../tests/conftest.p
## 4. Provider resolution
-Source: `LLMClient._resolve_provider()` in [`src/synth_panel/llm/client.py`](../src/synth_panel/llm/client.py).
+Source: `LLMClient._resolve_provider()` in [`src/althing/llm/client.py`](../src/althing/llm/client.py).
The flow on `client.send(request)`:
@@ -405,7 +405,7 @@ Providers are cached per-canonical-model-string inside the client, so `_resolve_
|---------|---------|-------|
| `_API_KEY` | `MISTRAL_API_KEY` | Required. Missing → `LLMError(MISSING_CREDENTIALS)`. |
| `_BASE_URL` | `MISTRAL_BASE_URL` | Optional. Overrides `default_base_url`. Users set this for proxies, VPC endpoints, or local mocks. |
-| `SYNTHPANEL_MODEL_ALIASES` | `'{"m-sm":"mistral-small-latest"}'` | Global. Users add their own aliases without touching code. |
+| `ALTHING_MODEL_ALIASES` | `'{"m-sm":"mistral-small-latest"}'` | Global. Users add their own aliases without touching code. |
If your provider needs additional config (a region, a project ID, an organization header), use the same `_*` prefix. Do not introduce unrelated variables — the MCP `env` block in editor configs is a flat dict, and convention is the only thing keeping it legible.
@@ -450,7 +450,7 @@ Work through this checklist before opening a PR:
- [ ] Unit tests cover: happy path, missing key, 429, 400, transport error, base URL override, streaming, deserialization failure
- [ ] Acceptance test present (skipped when API key is missing)
- [ ] `ruff check src/ tests/` clean
-- [ ] `mypy src/synth_panel/` clean
+- [ ] `mypy src/althing/` clean
- [ ] `CHANGELOG.md` `[Unreleased] → Added` entry
- [ ] `README.md` provider table row added (alphabetized inside the family, or placed beside the closest cousin)
- [ ] **SynthBench submission** (strongly recommended for adapter PRs) — run your adapter against SynthBench benchmarks and link the results in the PR description. See .
diff --git a/docs/agent-discovery-audit.md b/docs/agent-discovery-audit.md
index 79e69096..6e315c9a 100644
--- a/docs/agent-discovery-audit.md
+++ b/docs/agent-discovery-audit.md
@@ -1,4 +1,4 @@
-# SynthPanel Agent Discovery & Install Ergonomics Audit
+# Althing Agent Discovery & Install Ergonomics Audit
**Author:** crew/advo (Developer Advocate specialization)
**Date:** 2026-04-15
@@ -11,16 +11,16 @@ proposed.
## Executive Summary
-SynthPanel ships a capable product (v0.9.0, MIT-licensed, 12-tool MCP server,
+Althing ships a capable product (v0.9.0, MIT-licensed, 12-tool MCP server,
SPS 0.90 SynthBench score) but **its agent-facing surface is under-marketed on
every channel that matters for AI-era discovery**. The MCP server — the most
-differentiating agent-era feature — is a one-line footnote on synthpanel.dev, a
+differentiating agent-era feature — is a one-line footnote on althing.dev, a
section buried at line 335 of a 470-line README, and absent from every major
MCP registry.
LLM-based search ("does a tool for synthetic focus groups exist?") currently
returns Synthetic Users, FocusPanel.ai, Delve.ai, and POPJAM — **not
-SynthPanel**. The `"synthpanel" MCP` query surfaces zero indexed pages that
+Althing**. The `"althing" MCP` query surfaces zero indexed pages that
mention the project by name. The project is effectively invisible to the
agent-era discovery pipeline it is architecturally best positioned to serve.
@@ -31,7 +31,7 @@ content.
### Top 3 Quick Wins (hours)
-1. **Lift the MCP story to hero level on synthpanel.dev + README.** Today both
+1. **Lift the MCP story to hero level on althing.dev + README.** Today both
assets open with "terminal" framing; the `[mcp]` extra is a footnote. Add a
copy-paste-able Claude Code / Cursor / Windsurf JSON config block as
section 2, immediately after the install command.
@@ -48,7 +48,7 @@ content.
### Top 3 Bigger Plays (days)
-1. **AEO positioning content: "SynthPanel vs. Synthetic Users / FocusPanel.ai
+1. **AEO positioning content: "Althing vs. Synthetic Users / FocusPanel.ai
/ POPJAM — when open-source MCP beats the SaaS."** One 1500-word article
that LLMs can cite when asked about synthetic-respondent tools.
Independently valuable for GEO (generative engine optimization).
@@ -56,7 +56,7 @@ content.
Klavis.** Glama alone indexes 21,545 servers — we are not one of them.
Each is a separate free submission and each improves LLM retrieval.
3. **MCP-native README restructure + dedicated `/mcp` site route.** Today
- synthpanel.dev is a single page. A `/mcp` deep page that mirrors the
+ althing.dev is a single page. A `/mcp` deep page that mirrors the
reference-server pattern (tools list first, config-by-editor in ``
blocks, one-click VS Code install badges) gives both humans and crawlers a
canonical landing spot for agent-era discovery.
@@ -65,21 +65,21 @@ content.
## A. Audit of Current State
-### A.1 synthpanel.dev (live fetch, 2026-04-15)
+### A.1 althing.dev (live fetch, 2026-04-15)
| Signal | State | Gap |
|---|---|---|
-| `` | "synthpanel — Run synthetic focus groups with any LLM" | No "MCP", "agent", or "Claude Code" in the page title |
+| `` | "althing — Run synthetic focus groups with any LLM" | No "MCP", "agent", or "Claude Code" in the page title |
| Hero tagline | "Run synthetic focus groups with any LLM." | Frames the product as a CLI-first research tool, not agent-native |
| MCP mention | Single 9-word footnote under install command | Not positioned as a feature; no JSON snippet; no "Use with X" block |
| Cards | PyPI · GitHub · SynthBench | No MCP card; no Claude Code / Cursor / Windsurf card |
| Routes | `/` only (single-page site) | No `/mcp`, no `/docs`, no `/tools` — nothing for a crawler to index beyond the homepage |
-| `sitemap.xml` | Lists only `https://synthpanel.dev/` | Matches the single-page reality but caps the discoverable surface |
+| `sitemap.xml` | Lists only `https://althing.dev/` | Matches the single-page reality but caps the discoverable surface |
| OG / Twitter cards | Present, brief | Do not mention MCP or agent integration |
-| Canonical | `https://synthpanel.dev/` | Correct |
+| Canonical | `https://althing.dev/` | Correct |
**Verdict:** The site describes a CLI research tool. It does not advertise
-that SynthPanel is one of a small number of MCP-capable synthetic-research
+that Althing is one of a small number of MCP-capable synthetic-research
servers.
### A.2 README (`README.md`, 470 lines)
@@ -116,18 +116,18 @@ before bouncing. Reference Python MCP servers (e.g., `mcp-server-fetch`,
`mcp-server-git`) open with Tools + Install + Config in the top third; we do
the opposite.
-### A.3 PyPI metadata (verified via `https://pypi.org/pypi/synthpanel/json`)
+### A.3 PyPI metadata (verified via `https://pypi.org/pypi/althing/json`)
| Field | Value | Issue |
|---|---|---|
| `version` | `0.9.0` | Current |
| `summary` | "Run synthetic focus groups and user research panels using AI personas. CLI tool,…" | Truncated; omits "MCP / agent integration" |
| `home_page` | `null` | Legacy field unset — fine, `project_urls.Homepage` covers it |
-| `project_urls.Homepage` | `github.com/DataViking-Tech/synth-panel` | **Wrong repo name.** Canonical is `SynthPanel` (no hyphen). GitHub 301-redirects the old name via rename-redirect, but the URL shown to pip users is stale |
+| `project_urls.Homepage` | `github.com/DataViking-Tech/synth-panel` | **Wrong repo name.** Canonical is `Althing` (no hyphen). GitHub 301-redirects the old name via rename-redirect, but the URL shown to pip users is stale |
| `project_urls.Repository` | Same as above | Same issue |
| `project_urls.Changelog` | Same base URL | Same issue |
| `project_urls.Issues` | Same base URL | Same issue |
-| `project_urls` missing | No `Homepage = https://synthpanel.dev`, no `Documentation = https://synthpanel.dev/…`, no `Funding`, no "Use with Claude Code" link | Misses primary marketing channel |
+| `project_urls` missing | No `Homepage = https://althing.dev`, no `Documentation = https://althing.dev/…`, no `Funding`, no "Use with Claude Code" link | Misses primary marketing channel |
| `keywords` | `llm, research, focus-group, synthetic, personas, user-research, ai` | Missing: `mcp`, `model-context-protocol`, `agent`, `claude`, `claude-code`, `cursor`, `windsurf`, `survey-research`, `synthetic-respondents` |
| `classifiers` | 8 classifiers, only one agent-relevant: `Topic :: Scientific/Engineering :: Artificial Intelligence` | Missing: `Topic :: Software Development :: Libraries :: Python Modules`, `Topic :: Scientific/Engineering :: Information Analysis`, `Intended Audience :: Information Technology`, `Operating System :: OS Independent`, `Environment :: Console` |
@@ -135,7 +135,7 @@ the opposite.
algorithms on PyPI (and any downstream scraper — Glama, PulseMCP, etc.)
almost nothing to match an agent-era query against.
-### A.4 GitHub repo (`DataViking-Tech/SynthPanel`)
+### A.4 GitHub repo (`DataViking-Tech/Althing`)
| Signal | State | Gap |
|---|---|---|
@@ -152,7 +152,7 @@ almost nothing to match an agent-era query against.
`docs/mcp.md` is well-written: the 12 tools, 4 resources, 3 prompt templates,
response shape, data storage paths. It is the single best piece of agent-facing
documentation in the repo. **But it is not linked from the homepage, and
-synthpanel.dev does not render it.**
+althing.dev does not render it.**
---
@@ -160,7 +160,7 @@ synthpanel.dev does not render it.**
### B.1 MCP registry landscape (2026-04-15)
-| Registry | URL | Scale | SynthPanel listed? | Submission |
+| Registry | URL | Scale | Althing listed? | Submission |
|---|---|---|---|---|
| `punkpeye/awesome-mcp-servers` | github.com/punkpeye/awesome-mcp-servers | 84.8k ⭐, curated categories incl. **Research 🔬** | **No** | PR |
| `modelcontextprotocol/servers` (Resources section) | github.com/modelcontextprotocol/servers | Official; links out to community registries | **No** | PR |
@@ -176,7 +176,7 @@ analysis and Focus Group Interview (FGI) system that creates dynamic personas
from survey responses, generates contextual follow-up questions"). This is
significant: it means the category has traction in the registry, a search for
"persona" or "focus group" on glama.ai today surfaces a competitor, and a
-SynthPanel listing would compete directly.
+Althing listing would compete directly.
### B.2 Reference Python MCP server README pattern
@@ -195,7 +195,7 @@ Common structure:
Each shows a minimal JSON snippet.
5. **Debugging / Development / License.**
-**SynthPanel's README inverts this:** we lead with CLI usage, persona YAML,
+**Althing's README inverts this:** we lead with CLI usage, persona YAML,
instrument YAML, v3 branching (100+ lines), architecture — all before we get
to MCP. A reader looking for "can this be called by an agent?" has to scroll
through everything else first.
@@ -219,15 +219,15 @@ discussing `Framework :: MCP` on the Python Packaging Authority tracker but
nothing is accepted. Until it is, the right play is to **overload keywords**
(which PyPI search indexes) rather than wait for a classifier.
-### B.4 AEO / GEO audit — do LLMs know SynthPanel exists?
+### B.4 AEO / GEO audit — do LLMs know Althing exists?
Tested via WebSearch (simulating what modern LLMs retrieve):
-| Query | SynthPanel in top 10? | What shows up instead |
+| Query | Althing in top 10? | What shows up instead |
|---|---|---|
| `synthetic focus group AI personas tool open source MCP 2026` | **No** | Synthetic Users, FocusPanel.ai, Delve.ai, POPJAM, Maven course, lunar.dev |
-| `"synthpanel" MCP model context protocol` | **No** (zero matches for the quoted name) | Only generic MCP explainers |
-| `synthpanel Python AI personas focus group pip install` | **No** | Personaut, JasperHG90/persona, DSPy, AI-Persona-Lab, Sybil-Swarm |
+| `"althing" MCP model context protocol` | **No** (zero matches for the quoted name) | Only generic MCP explainers |
+| `althing Python AI personas focus group pip install` | **No** | Personaut, JasperHG90/persona, DSPy, AI-Persona-Lab, Sybil-Swarm |
**This is the clearest signal in the audit.** A user asking an LLM "is there
an open-source MCP server for synthetic focus groups?" today gets back a
@@ -248,7 +248,7 @@ are recorded after filing in the companion section of this document.
### C.1 Quick Wins (hours each)
-**Q1. Lift the MCP story above the fold on synthpanel.dev.**
+**Q1. Lift the MCP story above the fold on althing.dev.**
Add a prominent section between the install command and the Quick Start. Use
the reference-server pattern: one-line pitch + JSON config snippet + "Works
with Claude Code · Cursor · Windsurf · Zed" editor badge row. Include a
@@ -263,8 +263,8 @@ content but move it forward.
**Q3. Fix PyPI metadata.**
Edit `pyproject.toml`:
-- Change all 4 `project.urls` to canonical casing (`SynthPanel`, no hyphen)
- *and* add `Homepage = "https://synthpanel.dev"`, `Documentation = "https://synthpanel.dev"`, `"MCP Reference" = "https://github.com/DataViking-Tech/SynthPanel/blob/main/docs/mcp.md"`.
+- Change all 4 `project.urls` to canonical casing (`Althing`, no hyphen)
+ *and* add `Homepage = "https://althing.dev"`, `Documentation = "https://althing.dev"`, `"MCP Reference" = "https://github.com/DataViking-Tech/Althing/blob/main/docs/mcp.md"`.
- Expand `keywords` to include: `mcp`, `model-context-protocol`, `agent`,
`claude`, `claude-code`, `cursor`, `windsurf`, `survey-research`,
`synthetic-respondents`, `market-research`.
@@ -290,7 +290,7 @@ Current: 6 topics. Add: `model-context-protocol`, `claude-code`, `ai-agents`,
Single PR. Pattern for the entry (verbatim from list format):
```
-- [DataViking-Tech/SynthPanel](https://github.com/DataViking-Tech/SynthPanel)
+- [DataViking-Tech/Althing](https://github.com/DataViking-Tech/Althing)
📇 🐍 - Run synthetic focus groups with any LLM. 12 MCP tools: run_panel,
run_quick_poll, persona/instrument pack management. YAML-defined personas
and branching research instruments.
@@ -307,7 +307,7 @@ several LLMs cite those registries directly when asked "what MCP servers
exist for X."
**B3. Write an AEO positioning article.**
-Title candidate: *"SynthPanel vs. Synthetic Users vs. FocusPanel.ai — when
+Title candidate: *"Althing vs. Synthetic Users vs. FocusPanel.ai — when
open-source MCP beats the SaaS."* Publish on dataviking.tech /blog and
cross-post to Medium. Covers: (a) why LLM-agnostic matters (lock-in,
bring-your-own-key, cost control), (b) why YAML-defined instruments matter
@@ -317,14 +317,14 @@ clustering around means — we already document these in the README, lift
them into the article). Target: 1500 words, cite SynthBench SPS 0.90 as the
quantitative proof point.
-**B4. Add a dedicated `/mcp` deep page on synthpanel.dev.**
-Mirror `docs/mcp.md` as a static HTML page at `synthpanel.dev/mcp` — same
+**B4. Add a dedicated `/mcp` deep page on althing.dev.**
+Mirror `docs/mcp.md` as a static HTML page at `althing.dev/mcp` — same
content, indexable, with copy-buttons on every config block. Add a sitemap
entry. Link from the hero card row. This gives LLMs and search engines a
canonical agent-integration landing page that they can cite.
**B5. Add a custom social preview card to the GitHub repo.**
-1280×640 PNG showing "SynthPanel · MCP server for synthetic focus groups ·
+1280×640 PNG showing "Althing · MCP server for synthetic focus groups ·
12 tools · any LLM." Uploaded via repo Settings. Shows up every time the
repo is linked in Slack, Discord, or HN. One afternoon of design work.
@@ -340,19 +340,19 @@ it exists.
For the record, I considered and rejected:
-1. **Renaming the PyPI package to `mcp-server-synthpanel`** — follows the
+1. **Renaming the PyPI package to `mcp-server-althing`** — follows the
reference-server convention but breaks every existing installation,
documentation link, and the brand. The convention is for servers that
- are *only* MCP. SynthPanel is also a CLI + Python library. Keep the
+ are *only* MCP. Althing is also a CLI + Python library. Keep the
current name; surface MCP-ness through the metadata and content layers.
2. **Splitting the MCP server into its own package** — same argument.
- Current packaging (`pip install synthpanel[mcp]`) is the right call.
+ Current packaging (`pip install althing[mcp]`) is the right call.
3. **Chasing a `Framework :: MCP` PyPI classifier** — no upstream consensus
yet. Revisit in 6 months.
4. **Paying for hosted MCP registry placement (Smithery)** — not needed
when free registries (Glama, PulseMCP, awesome-list) cover the same
retrieval surface. Reconsider if traction warrants.
-5. **Changing the `synthpanel mcp-serve` CLI entrypoint name** — it's
+5. **Changing the `althing mcp-serve` CLI entrypoint name** — it's
non-canonical (`mcp-server-*` is the convention) but changing it is a
breaking change for any existing user's config. Document, don't rename.
@@ -361,14 +361,14 @@ For the record, I considered and rejected:
## E. Methodology and Verification
- All live-page findings verified via `curl`/WebFetch on 2026-04-15.
-- PyPI metadata verified via the JSON API (`/pypi/synthpanel/json`).
+- PyPI metadata verified via the JSON API (`/pypi/althing/json`).
- Classifier recommendations cross-checked against currently-accepted values
at .
- Awesome-list category structure verified by fetching raw `README.md` from
`punkpeye/awesome-mcp-servers` (84.8k ⭐ as of fetch).
- AEO queries run via web search in April 2026; results are retrieval-layer
snapshots, not a permanent claim about what every LLM knows.
-- The `synth-panel` → `SynthPanel` URL redirect was verified with `curl -I` —
+- The `synth-panel` → `Althing` URL redirect was verified with `curl -I` —
the hyphenated URL returns `HTTP 301` to the canonical; no broken links,
but the metadata is stale.
@@ -380,15 +380,15 @@ Filed 2026-04-15 as hierarchical children of `sp-ege`, all priority P3 (backlog)
| Bead | Title | Category |
|---|---|---|
-| `sp-ege.1` | Lift MCP story above the fold on synthpanel.dev | Quick win (site) |
+| `sp-ege.1` | Lift MCP story above the fold on althing.dev | Quick win (site) |
| `sp-ege.2` | Lift MCP section to README position 2 (after Quick Start) | Quick win (README) |
| `sp-ege.3` | Fix PyPI metadata: URLs, keywords, classifiers (v0.9.1 patch) | Quick win (PyPI) |
| `sp-ege.4` | Add "Use with Claude Code / Cursor / Windsurf / Zed" section to README | Quick win (README) |
| `sp-ege.5` | GitHub repo hygiene: topics + social preview + About description | Quick win (GitHub) |
-| `sp-ege.6` | Submit SynthPanel to `punkpeye/awesome-mcp-servers` (Research category) | Bigger play (ecosystem) |
+| `sp-ege.6` | Submit Althing to `punkpeye/awesome-mcp-servers` (Research category) | Bigger play (ecosystem) |
| `sp-ege.7` | Multi-registry submission sweep: Glama, PulseMCP, MCPHub, Klavis | Bigger play (ecosystem) |
-| `sp-ege.8` | Write AEO positioning article: SynthPanel vs commercial alternatives | Bigger play (content) |
-| `sp-ege.9` | Add `/mcp` deep page to synthpanel.dev | Bigger play (site) |
+| `sp-ege.8` | Write AEO positioning article: Althing vs commercial alternatives | Bigger play (content) |
+| `sp-ege.9` | Add `/mcp` deep page to althing.dev | Bigger play (site) |
Each bead carries its own acceptance criteria, labels (`discovery`, plus
one of `site`/`readme`/`pypi`/`github`/`registry`/`content`), and may be
diff --git a/docs/agent-integration-landscape.md b/docs/agent-integration-landscape.md
index 1f9367bf..da2a42ef 100644
--- a/docs/agent-integration-landscape.md
+++ b/docs/agent-integration-landscape.md
@@ -1,4 +1,4 @@
-# SynthPanel Agent Integration Landscape: Beyond MCP
+# Althing Agent Integration Landscape: Beyond MCP
**Author:** crew/advo (Developer Advocate specialization)
**Date:** 2026-04-15
@@ -10,34 +10,34 @@
## Executive Summary
-SynthPanel's MCP server is better-positioned than we thought. The major agent
+Althing's MCP server is better-positioned than we thought. The major agent
frameworks — OpenAI Agents SDK, LlamaIndex, CrewAI, Microsoft Agent Framework
1.0, n8n, Zapier, and VS Code AI Toolkit — **all now support MCP as a
-first-class tool integration path**. This means SynthPanel's 12-tool MCP
+first-class tool integration path**. This means Althing's 12-tool MCP
server already works with every major framework. There is no urgent need to
ship native framework-specific tool wrappers.
The gap is not capability — it's **discoverability and ergonomics**. Nobody
-knows SynthPanel works with LangChain/CrewAI/OpenAI Agents because there are
+knows Althing works with LangChain/CrewAI/OpenAI Agents because there are
no examples, no docs, no proof. And for programmatic use (scripts, pipelines,
notebooks), spawning an MCP server process is heavier than a direct Python
import.
### Recommendation: Next 3 After MCP
-1. **Public Python SDK convenience layer** — `from synth_panel import
+1. **Public Python SDK convenience layer** — `from althing import
quick_poll, run_panel`. The highest-impact, lowest-effort addition.
Serves both human developers and any Python-based agent framework
directly. No MCP overhead.
2. **Agent framework examples + "Works with X" documentation** — Five
- example scripts proving SynthPanel works with LangChain, CrewAI,
+ example scripts proving Althing works with LangChain, CrewAI,
OpenAI Agents SDK, LlamaIndex, and Microsoft Agent Framework via MCP.
Zero library code — just examples that prove the MCP bridge works.
Each example becomes a searchable, AEO-indexable content page.
3. **Composio connector** — One listing in the Composio marketplace
- (850+ tools) gives SynthPanel simultaneous presence in LangChain,
+ (850+ tools) gives Althing simultaneous presence in LangChain,
CrewAI, Semantic Kernel, and AutoGen tool catalogs. This is the
highest-leverage marketplace play.
@@ -45,11 +45,11 @@ import.
## A. Current Integration Surfaces (Inventory)
-SynthPanel ships five integration surfaces today:
+Althing ships five integration surfaces today:
| Surface | State | Agent-Reachable? |
|---|---|---|
-| **CLI** (`synthpanel` command) | Full-featured, all commands | Yes — any agent can shell out |
+| **CLI** (`althing` command) | Full-featured, all commands | Yes — any agent can shell out |
| **Python library** (internal functions) | `orchestrator.run_panel_parallel()`, `run_multi_round_panel()`, `ensemble_run()` exist but are internal implementation functions | Partial — importable, but no documented public API; no `__all__` exports at package level; no convenience wrappers |
| **MCP server** (12 tools, 4 resources, 3 prompts) | FastMCP, stdio transport, defaults to haiku | Yes — primary agent interface |
| **Claude Code plugin** (`.claude-plugin/plugin.json`) | Wraps MCP server + ships `/focus-group` skill | Yes — Claude Code only |
@@ -58,7 +58,7 @@ SynthPanel ships five integration surfaces today:
**Key observations:**
- The MCP server is the only general-purpose agent interface.
- The Python library has the functions but no public API surface: no
- `from synth_panel import quick_poll`, no documented entry points,
+ `from althing import quick_poll`, no documented entry points,
no `__init__.py` exports at the package level.
- The Claude Code plugin and skill are well-built but serve one editor only.
- No framework-specific wrappers exist (LangChain, CrewAI, etc.).
@@ -71,14 +71,14 @@ SynthPanel ships five integration surfaces today:
The most important finding in this research: **MCP has won the agent tool
integration protocol war**. Every major agent framework now supports MCP as a
-first-class tool source. This changes the calculus for SynthPanel's
+first-class tool source. This changes the calculus for Althing's
integration strategy.
### Framework-by-framework MCP support (verified April 2026)
| Framework | MCP Support | How It Works | Native Wrapper Needed? |
|---|---|---|---|
-| **OpenAI Agents SDK** | Built-in | `MCPServerStdio("synthpanel", ["mcp-serve"])` → agent auto-discovers 12 tools | **No** |
+| **OpenAI Agents SDK** | Built-in | `MCPServerStdio("althing", ["mcp-serve"])` → agent auto-discovers 12 tools | **No** |
| **LlamaIndex** | `llama-index-tools-mcp` (v0.4.8, Feb 2026) | `BasicMCPClient` → `mcp_tool_spec.to_tool_list()` → agent uses tools | **No** |
| **CrewAI** | `crewai-tools[mcp]` | MCP server as tool source | **No** |
| **Microsoft Agent Framework 1.0** | Built-in MCP clients (April 2026) | MCP client in agent config → auto-discover tools | **No** |
@@ -87,7 +87,7 @@ integration strategy.
| **Zapier** | Zapier MCP (30K+ actions) | Supports custom MCP servers | **No** |
| **VS Code AI Toolkit** | First-class MCP tool type (March 2026) | MCP server in tool catalog | **No** |
-**The implication:** Shipping native `SynthPanelTool` wrappers for each
+**The implication:** Shipping native `AlthingTool` wrappers for each
framework is busywork with declining marginal value. The frameworks already
bridge MCP. The right strategy is to:
1. Keep the MCP server excellent.
@@ -100,8 +100,8 @@ MCP is optimized for editor-hosted agents (Claude Code, Cursor, Windsurf)
where a long-lived stdio server process is natural. It's less ergonomic for:
- **Programmatic use in scripts/pipelines/notebooks** — spawning a subprocess
- for `synthpanel mcp-serve` just to call `quick_poll` adds latency and
- complexity. A direct `from synth_panel import quick_poll` is simpler.
+ for `althing mcp-serve` just to call `quick_poll` adds latency and
+ complexity. A direct `from althing import quick_poll` is simpler.
- **Serverless/ephemeral environments** — Lambda, Cloud Run, GitHub Actions
can't easily run a stdio server. A direct function call or HTTP endpoint
is needed.
@@ -121,7 +121,7 @@ with MCP. It serves the use cases MCP doesn't.
**What:** Export clean public functions at the package level so users can do:
```python
-from synth_panel import quick_poll, run_panel, list_instruments
+from althing import quick_poll, run_panel, list_instruments
# One-liner: poll 5 personas on a question
results = quick_poll("What do you think of the name Traitprint?")
@@ -143,7 +143,7 @@ results = run_panel(
```python
from langchain_core.tools import tool
-from synth_panel import quick_poll
+from althing import quick_poll
@tool
def synthetic_focus_group(question: str) -> str:
@@ -162,7 +162,7 @@ thin wrappers around the orchestrator + MCP server logic, add `__all__`
exports, write docstrings, add `examples/sdk_usage.py`.
**Impact:** HIGH. This is the most broadly useful integration surface after
-MCP. Every Python developer who discovers SynthPanel via PyPI, pip, or import
+MCP. Every Python developer who discovers Althing via PyPI, pip, or import
gets a zero-friction onramp.
### C.2 Agent Framework Examples + "Works with X" Documentation
@@ -182,12 +182,12 @@ Plus a README section: "Works with LangChain, CrewAI, OpenAI Agents, LlamaIndex,
Microsoft Agent Framework, n8n, Zapier — any framework that supports MCP."
**Why it matters:**
-- The MCP convergence thesis means SynthPanel already works with these
+- The MCP convergence thesis means Althing already works with these
frameworks — but nobody knows it. Zero examples exist.
- Each example is an independently indexable, searchable content page.
- A developer searching "how to run synthetic focus group from LangChain"
- finds this and discovers SynthPanel.
-- sp-ege found SynthPanel invisible to AEO queries. Integration examples
+ finds this and discovers Althing.
+- sp-ege found Althing invisible to AEO queries. Integration examples
create exactly the kind of content that LLMs cite.
**Effort:** 1-2 days. Write 5-6 scripts, test each, add README section.
@@ -197,20 +197,20 @@ disguised as developer documentation.
### C.3 Composio Connector
-**What:** Register SynthPanel as a tool in the Composio marketplace (850+
+**What:** Register Althing as a tool in the Composio marketplace (850+
tools, used by LangChain, CrewAI, Semantic Kernel, AutoGen).
**Why it matters:**
- One listing = presence in all major framework tool catalogs simultaneously.
- Composio handles auth, rate limiting, schema validation.
- A developer browsing Composio's tool catalog for "survey" or "focus group"
- finds SynthPanel.
+ finds Althing.
- Composio's connectors are the modern equivalent of an npm package — they
compound discovery.
**What it requires:**
- Composio uses a connector format (likely OpenAPI spec + auth config).
-- SynthPanel would need to expose either its MCP tools via a thin HTTP API
+- Althing would need to expose either its MCP tools via a thin HTTP API
wrapper, or provide a Python function-based connector.
- Composio supports "bring your own tool" — the connector runs locally.
@@ -221,7 +221,7 @@ test with LangChain + CrewAI, submit to Composio's marketplace.
Composio's tooling, which has its own learning curve.
**Status (2026-04-16):** Connector code committed in
-[`src/synth_panel/integrations/composio.py`](../src/synth_panel/integrations/composio.py);
+[`src/althing/integrations/composio.py`](../src/althing/integrations/composio.py);
LangChain and CrewAI examples in
[`examples/integrations/`](../examples/integrations/); marketplace submission
runbook at [`docs/composio-submission.md`](composio-submission.md). Only the
@@ -254,21 +254,21 @@ purpose-built skills:
pattern. The `/focus-group` skill is a proven template.
**Impact:** MEDIUM-HIGH within the Claude Code ecosystem; zero impact outside
-it. Good leverage because Claude Code is SynthPanel's most natural home —
+it. Good leverage because Claude Code is Althing's most natural home —
an agent that can invoke MCP tools is the target user.
### C.5 Docker Image
-**What:** Publish a Docker image that runs `synthpanel mcp-serve` (and/or
+**What:** Publish a Docker image that runs `althing mcp-serve` (and/or
exposes the Python SDK as an HTTP API).
```bash
-docker run -e ANTHROPIC_API_KEY=sk-... synthpanel/synthpanel mcp-serve
+docker run -e ANTHROPIC_API_KEY=sk-... althing/althing mcp-serve
```
**Why it matters:**
- Agents in serverless environments (Lambda, Cloud Run, GitHub Actions)
- can spin up a SynthPanel container as a tool-call target.
+ can spin up a Althing container as a tool-call target.
- n8n, Zapier, and custom orchestrators that support Docker-based tools
get a zero-install path.
@@ -306,10 +306,10 @@ ratio is poor compared to other options.
### C.7 Custom GPT / OpenAI Plugin
-**What:** A ChatGPT-hosted wrapper around SynthPanel.
+**What:** A ChatGPT-hosted wrapper around Althing.
**Why to defer:**
-- SynthPanel is local-first (bring-your-own-key, run on your machine).
+- Althing is local-first (bring-your-own-key, run on your machine).
A Custom GPT inverts this by requiring a hosted API endpoint.
- OpenAI Agents SDK already supports MCP — the programmatic path is
covered.
@@ -324,7 +324,7 @@ research.
### C.8 Webhook / Event-Driven Pattern
-**What:** SynthPanel as a service that agents POST to and receive results
+**What:** Althing as a service that agents POST to and receive results
asynchronously (webhook callback or polling).
**Why to defer:**
@@ -332,7 +332,7 @@ asynchronously (webhook callback or polling).
- No demonstrated demand.
- MCP's stdio transport and the Python SDK cover the two main invocation
patterns (editor-hosted agent and programmatic script).
-- Worth revisiting if SynthPanel ever ships a hosted/cloud offering.
+- Worth revisiting if Althing ever ships a hosted/cloud offering.
**Effort:** 1-2 weeks.
@@ -340,8 +340,8 @@ asynchronously (webhook callback or polling).
### C.9 Native Framework Tool Wrappers
-**What:** `pip install synthpanel-langchain`, `pip install synthpanel-crewai`,
-etc. Each is a thin Python package that wraps SynthPanel's MCP tools (or
+**What:** `pip install althing-langchain`, `pip install althing-crewai`,
+etc. Each is a thin Python package that wraps Althing's MCP tools (or
direct SDK) as framework-native tools.
**Why to skip (for now):**
@@ -361,9 +361,9 @@ in examples that prove MCP works.
## D. Competitor Integration Surface Comparison
-| Feature | SynthPanel | Synthetic Users | FocusPanel.ai |
+| Feature | Althing | Synthetic Users | FocusPanel.ai |
|---|---|---|---|
-| CLI | Yes (`synthpanel`) | No | No |
+| CLI | Yes (`althing`) | No | No |
| Python SDK | Internal functions (no public API) | Python + TypeScript SDKs (MIT) | Unknown |
| MCP server | Yes (12 tools, stdio) | No | No |
| Claude Code plugin | Yes | No | No |
@@ -375,7 +375,7 @@ in examples that prove MCP works.
| Open source | Yes (MIT) | Yes (MIT) | No (SaaS) |
| Pricing | Free (BYOK) | SaaS | SaaS |
-**SynthPanel's differentiation:**
+**Althing's differentiation:**
- Only synthetic-research tool with MCP support (agent-native by design).
- Only open-source option with CLI + MCP + Claude Code plugin.
- BYOK (bring your own key) vs SaaS lock-in.
@@ -384,19 +384,19 @@ in examples that prove MCP works.
---
-## E. The "Agent Reaches for SynthPanel Automatically" Question
+## E. The "Agent Reaches for Althing Automatically" Question
-The bead asks: *"What patterns would make SynthPanel the default tool that
+The bead asks: *"What patterns would make Althing the default tool that
agents reach for automatically?"*
This is fundamentally an **AEO + registry + content** problem, not a
code problem. An agent's tool-selection is determined by:
1. **What tools are registered** — MCP config, Composio catalog, framework
- tool list. If SynthPanel's MCP server is in the agent's config, it's
+ tool list. If Althing's MCP server is in the agent's config, it's
reachable.
2. **What the LLM knows** — training data, retrieval-augmented context,
- indexed documentation. If the LLM has never seen "synthpanel" in its
+ indexed documentation. If the LLM has never seen "althing" in its
training or retrieval corpus, it can't recommend it.
3. **How tools are described** — the MCP server's tool names and descriptions
determine whether the LLM selects them for a given task.
@@ -406,12 +406,12 @@ addresses #1 (integration surfaces) and #3 (tool descriptions). Together
they form a complete strategy:
- **Short term:** Fix MCP registry presence (sp-ege beads) + ship
- integration examples (this audit) = agents can find and use SynthPanel.
+ integration examples (this audit) = agents can find and use Althing.
- **Medium term:** Public Python SDK + Composio listing + AEO content =
- SynthPanel becomes the default answer when an agent (or a human using an
+ Althing becomes the default answer when an agent (or a human using an
agent) asks "how do I run a synthetic focus group?"
- **Long term:** Skills library + Docker image + eventual REST API =
- SynthPanel is reachable from every invocation pattern (editor, script,
+ Althing is reachable from every invocation pattern (editor, script,
serverless, workflow, marketplace).
---
@@ -460,8 +460,8 @@ they form a complete strategy:
- Custom slash commands: [code.claude.com/docs/en/slash-commands](https://code.claude.com/docs/en/slash-commands) — `.claude/commands/` and `.claude/skills/` directories
### Internal code audit
-- `src/synth_panel/orchestrator.py`: `run_panel_parallel()` (line 501), `run_multi_round_panel()` (line 638), `ensemble_run()` (line 847)
-- `src/synth_panel/mcp/server.py`: 12 tool handlers wrapping orchestrator functions
+- `src/althing/orchestrator.py`: `run_panel_parallel()` (line 501), `run_multi_round_panel()` (line 638), `ensemble_run()` (line 847)
+- `src/althing/mcp/server.py`: 12 tool handlers wrapping orchestrator functions
- `.claude-plugin/plugin.json`: MCP server config + skill reference
- `skills/focus-group/SKILL.md`: 5-step workflow skill
@@ -475,7 +475,7 @@ Filed 2026-04-15 as hierarchical children of `sp-2cw`, all priority P3 (backlog)
|---|---|---|
| `sp-2cw.1` | Design & ship public Python SDK convenience layer | **Top 3 — highest impact** |
| `sp-2cw.2` | Write "Works with X" integration examples for 5 agent frameworks | **Top 3 — highest impact** |
-| `sp-2cw.3` | Register SynthPanel as a Composio connector | **Top 3 — highest impact** |
+| `sp-2cw.3` | Register Althing as a Composio connector | **Top 3 — highest impact** |
| `sp-2cw.4` | Expand Claude Code skills library beyond `/focus-group` | Second tier |
| `sp-2cw.5` | Publish Docker image for ephemeral/serverless agent invocation | Second tier |
| `sp-2cw.6` | Add "Works with" section to README linking integration examples | Second tier (bundle with sp-2cw.2) |
@@ -483,7 +483,7 @@ Filed 2026-04-15 as hierarchical children of `sp-2cw`, all priority P3 (backlog)
**Explicitly not filed** (recommendation: skip):
- Native LangChain/CrewAI/LlamaIndex tool wrappers → redundant with MCP bridges
-- Custom GPT / OpenAI plugin → inverts SynthPanel's local-first architecture
+- Custom GPT / OpenAI plugin → inverts Althing's local-first architecture
- Webhook/event-driven service → no demonstrated demand
- Native n8n/Zapier nodes → both platforms already support MCP
diff --git a/docs/agent-quickstart.md b/docs/agent-quickstart.md
index ce141bfe..1e7a73b6 100644
--- a/docs/agent-quickstart.md
+++ b/docs/agent-quickstart.md
@@ -11,7 +11,7 @@ engine — pick the one that matches your runtime:
- **[CLI path](#cli-path)** — shell agents, CI, terminals.
- **[MCP path](#mcp-path)** — editor and framework agents that call tools.
-Every command and number below was captured on a recent `synthpanel` release
+Every command and number below was captured on a recent `althing` release
(the exact version and Python patch your machine prints will differ). Costs are the
CLI's own pre-flight estimates (Haiku pricing) — your run will print the actual
spend.
@@ -31,14 +31,14 @@ spend.
Pick the install that matches how you use Python tools:
```bash
-pip install synthpanel # in your project venv (library + CLI)
-pip install 'synthpanel[mcp]' # also want the MCP server
-pipx install synthpanel # global, isolated, on your PATH
-uvx --from synthpanel synthpanel --help # zero-install, run once
+pip install althing # in your project venv (library + CLI)
+pip install 'althing[mcp]' # also want the MCP server
+pipx install althing # global, isolated, on your PATH
+uvx --from althing althing --help # zero-install, run once
```
-The PyPI distribution and CLI are spelled **`synthpanel`** (one word); the
-importable module is **`synth_panel`** (snake_case). Both resolve to the same
+The PyPI distribution and CLI are spelled **`althing`** (one word); the
+importable module is **`althing`** (snake_case). Both resolve to the same
code.
### 2. Verify the install (no key needed)
@@ -48,17 +48,17 @@ when the package, deps, and bundled packs are healthy — even with no credentia
— so it's the canonical post-install smoke test:
```bash
-synthpanel --version # entry point dispatches
-synthpanel doctor --install-only # install health only — no key required
+althing --version # entry point dispatches
+althing doctor --install-only # install health only — no key required
```
```text
-synthpanel 1.5.7
+althing 1.5.7
✓ python: 3.12.7 (>= 3.10)
✓ required deps: httpx, pyyaml
✓ optional: mcp installed
- ! credentials: none configured (install-only mode — run `synthpanel login` before running a panel).
- ✓ checkpoint root: ~/.synthpanel/checkpoints (writable, 0 existing runs)
+ ! credentials: none configured (install-only mode — run `althing login` before running a panel).
+ ✓ checkpoint root: ~/.althing/checkpoints (writable, 0 existing runs)
✓ packs: 14 persona, 8 instrument (bundled)
1 warning, 0 errors.
```
@@ -68,7 +68,7 @@ For machine consumption, the JSON form separates `install_ok`,
each surface independently:
```bash
-synthpanel --output-format json doctor --install-only
+althing --output-format json doctor --install-only
```
### 3. Configure a provider
@@ -78,11 +78,11 @@ provider. Export it, or persist it once:
```bash
export ANTHROPIC_API_KEY="sk-..."
-# or store it (written to ~/.config/synthpanel/credentials.json, mode 0600):
-synthpanel login --provider anthropic --api-key sk-...
+# or store it (written to ~/.config/althing/credentials.json, mode 0600):
+althing login --provider anthropic --api-key sk-...
-synthpanel whoami # which providers now resolve
-synthpanel doctor # full preflight: install + credentials (exits 1 if none)
+althing whoami # which providers now resolve
+althing doctor # full preflight: install + credentials (exits 1 if none)
```
### 4. Dry-run first
@@ -92,7 +92,7 @@ count, and a cost estimate — **without making any LLM calls**. Always dry-run
before spending tokens, especially in autonomous loops:
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml \
--model haiku \
@@ -115,7 +115,7 @@ Drop `--dry-run` to execute. The chosen model is printed to stderr before the
run so you can cancel and override:
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml \
--model haiku
@@ -132,11 +132,11 @@ them with `--personas-merge` (duplicate names are de-duped, later file wins, and
a warning names every drop):
```bash
-synthpanel pack list # 14 bundled packs, with counts
-synthpanel pack export product-research -o pr.yaml # 20 personas
-synthpanel pack export broad-professionals -o bp.yaml # 20 personas
+althing pack list # 14 bundled packs, with counts
+althing pack export product-research -o pr.yaml # 20 personas
+althing pack export broad-professionals -o bp.yaml # 20 personas
-synthpanel panel run \
+althing panel run \
--personas pr.yaml \
--personas-merge bp.yaml \
--instrument examples/survey.yaml \
@@ -157,20 +157,20 @@ Drop `--dry-run` to run it. Use `--max-cost 0.50` to hard-cap spend and
### 7. Save and emit JSON
-`--save` writes the full result to `~/.synthpanel/results`; the global
+`--save` writes the full result to `~/.althing/results`; the global
`--output-format json` flag emits the same machine-readable envelope you'd get
from the MCP `run_panel` tool:
```bash
-synthpanel --output-format json panel run \
+althing --output-format json panel run \
--personas pr.yaml \
--personas-merge bp.yaml \
--instrument examples/survey.yaml \
--model haiku \
--save > result.json
-synthpanel results list # what's saved on disk
-synthpanel report # render a shareable Markdown report
+althing results list # what's saved on disk
+althing report # render a shareable Markdown report
```
The JSON envelope (abridged):
@@ -202,7 +202,7 @@ envelope is documented in
## MCP path
-Editor and framework agents call SynthPanel as MCP tools instead of shelling
+Editor and framework agents call Althing as MCP tools instead of shelling
out. The server launches on demand over stdio — no long-running process.
### 1. Register the server
@@ -211,10 +211,10 @@ The `mcp install` helper writes the config entry for you (Claude Code user scope
by default; `--target` for other hosts):
```bash
-synthpanel mcp install # ~/.claude.json (all projects)
-synthpanel mcp install --scope project # ./.mcp.json (checked in, shared)
-synthpanel mcp install --target ~/.cursor/mcp.json # Cursor
-synthpanel mcp install --dry-run # print JSON, change nothing
+althing mcp install # ~/.claude.json (all projects)
+althing mcp install --scope project # ./.mcp.json (checked in, shared)
+althing mcp install --target ~/.cursor/mcp.json # Cursor
+althing mcp install --dry-run # print JSON, change nothing
```
Or write the config by hand. The generic stdio entry every MCP host
@@ -223,8 +223,8 @@ understands:
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -236,8 +236,8 @@ Host-specific snippets — Claude Code, Cursor, Windsurf, Zed (uses
`context_servers`), Hermes (YAML with explicit timeouts), and Claude Desktop —
are in the README's [Use with Claude Code / Cursor / Windsurf /
Zed](../README.md#use-with-claude-code--cursor--windsurf--zed) section. If
-`synthpanel` lives in a virtualenv, point `command` at its absolute path
-(e.g. `/path/to/.venv/bin/synthpanel`).
+`althing` lives in a virtualenv, point `command` at its absolute path
+(e.g. `/path/to/.venv/bin/althing`).
### 2. Call the research tools
@@ -301,7 +301,7 @@ instrument:
```
```bash
-synthpanel --output-format json panel run \
+althing --output-format json panel run \
--personas pr.yaml \
--instrument pricing-poll.yaml \
--model haiku \
@@ -314,8 +314,8 @@ For a deterministic vote/score rollup — no LLM, no parsing — run `poll-summa
on the saved result:
```bash
-synthpanel poll-summary --format json
-synthpanel poll-summary --segment-by occupation # split the vote by attribute
+althing poll-summary --format json
+althing poll-summary --segment-by occupation # split the vote by attribute
```
`response_schema` types are `enum` (pick-one), `scale` (Likert/rating), `text`
diff --git a/docs/agent-skills.md b/docs/agent-skills.md
index e1ae69b9..9e4fb615 100644
--- a/docs/agent-skills.md
+++ b/docs/agent-skills.md
@@ -1,20 +1,20 @@
# Agent Skills & Slash Commands
-synthpanel ships seven Claude Code-native artifacts that drive the MCP
-server: one slash command (`/synthpanel-poll`), one top-level director
-skill (`synthpanel`), and five workflow skills (`focus-group`,
+althing ships seven Claude Code-native artifacts that drive the MCP
+server: one slash command (`/althing-poll`), one top-level director
+skill (`althing`), and five workflow skills (`focus-group`,
`name-test`, `concept-test`, `survey-prescreen`, `pricing-probe`). They
live at the repository root in [`commands/`](../commands/) and
[`skills/`](../skills/), and Claude Code discovers them from the local
filesystem rather than from the installed Python package — so
-`pip install synthpanel[mcp]` alone doesn't expose them. This page
+`pip install althing[mcp]` alone doesn't expose them. This page
documents how to install them.
The skill files follow the open
[Agent Skills Discovery](https://agentskills.io/) format, so
[Hermes Agent](https://hermes-agent.nousresearch.com/), Codex CLI,
Cursor, Goose, OpenHands, and other skills-compatible hosts can load
-them with the same files. The `synthpanel` director skill in particular
+them with the same files. The `althing` director skill in particular
includes Hermes-specific frontmatter (`metadata.hermes.*`,
`required_environment_variables`) so Hermes can install and configure
it without ad-hoc spelunking.
@@ -23,15 +23,15 @@ it without ad-hoc spelunking.
| Artifact | File | Type | Triggers |
|---|---|---|---|
-| `/synthpanel-poll ` | [`commands/synthpanel-poll.md`](../commands/synthpanel-poll.md) | Slash command | One-question quick poll |
-| `synthpanel` | [`skills/synthpanel/SKILL.md`](../skills/synthpanel/SKILL.md) | Skill (director) | "run a synthetic panel", "test positioning", "compare names", "pricing probe", "poll N personas", "prioritization poll" |
+| `/althing-poll ` | [`commands/althing-poll.md`](../commands/althing-poll.md) | Slash command | One-question quick poll |
+| `althing` | [`skills/althing/SKILL.md`](../skills/althing/SKILL.md) | Skill (director) | "run a synthetic panel", "test positioning", "compare names", "pricing probe", "poll N personas", "prioritization poll" |
| `focus-group` | [`skills/focus-group/SKILL.md`](../skills/focus-group/SKILL.md) | Skill | Full focus-group workflow |
| `name-test` | [`skills/name-test/SKILL.md`](../skills/name-test/SKILL.md) | Skill | 1–3 candidate name comparison |
| `concept-test` | [`skills/concept-test/SKILL.md`](../skills/concept-test/SKILL.md) | Skill | Concept / value-prop validation |
| `survey-prescreen` | [`skills/survey-prescreen/SKILL.md`](../skills/survey-prescreen/SKILL.md) | Skill | Pre-screen a survey instrument |
| `pricing-probe` | [`skills/pricing-probe/SKILL.md`](../skills/pricing-probe/SKILL.md) | Skill | Pricing sensitivity probe |
-All seven call into the synthpanel MCP server, so the
+All seven call into the althing MCP server, so the
[MCP server](mcp.md) must be configured first — none of these work
standalone.
@@ -46,13 +46,13 @@ If you use Claude Code, install the bundled plugin and you get
everything in one shot — no file copying:
```
-/plugin install synthpanel
+/plugin install althing
```
The plugin manifest at [`.claude-plugin/plugin.json`](../.claude-plugin/plugin.json)
registers the MCP server and points Claude Code at all six artifacts
under `commands/` and `skills/`. Restart Claude Code after install and
-`/synthpanel-poll` plus the five skills are available.
+`/althing-poll` plus the five skills are available.
### 2. Manual copy into Claude Code (any project, no plugin)
@@ -67,37 +67,37 @@ From a clone of this repo:
```bash
# User-scope install — every project gets the artifacts
mkdir -p ~/.claude/commands ~/.claude/skills
-cp commands/synthpanel-poll.md ~/.claude/commands/
-cp -r skills/synthpanel skills/focus-group skills/name-test \
+cp commands/althing-poll.md ~/.claude/commands/
+cp -r skills/althing skills/focus-group skills/name-test \
skills/concept-test skills/survey-prescreen skills/pricing-probe \
~/.claude/skills/
# OR project-scope install — only this project gets the artifacts
mkdir -p .claude/commands .claude/skills
-cp commands/synthpanel-poll.md .claude/commands/
-cp -r skills/synthpanel skills/focus-group skills/name-test \
+cp commands/althing-poll.md .claude/commands/
+cp -r skills/althing skills/focus-group skills/name-test \
skills/concept-test skills/survey-prescreen skills/pricing-probe \
.claude/skills/
```
-Restart Claude Code. `/synthpanel-poll "your question"` and the six
-skills (`synthpanel`, `focus-group`, `name-test`, etc.) are now
+Restart Claude Code. `/althing-poll "your question"` and the six
+skills (`althing`, `focus-group`, `name-test`, etc.) are now
available.
If you don't have a clone, fetch the files directly from GitHub:
```bash
-SP_RAW=https://raw.githubusercontent.com/DataViking-Tech/SynthPanel/main
+SP_RAW=https://raw.githubusercontent.com/DataViking-Tech/Althing/main
mkdir -p ~/.claude/commands \
- ~/.claude/skills/synthpanel ~/.claude/skills/focus-group \
+ ~/.claude/skills/althing ~/.claude/skills/focus-group \
~/.claude/skills/name-test ~/.claude/skills/concept-test \
~/.claude/skills/survey-prescreen ~/.claude/skills/pricing-probe
-curl -fsSL $SP_RAW/commands/synthpanel-poll.md \
- -o ~/.claude/commands/synthpanel-poll.md
+curl -fsSL $SP_RAW/commands/althing-poll.md \
+ -o ~/.claude/commands/althing-poll.md
-for s in synthpanel focus-group name-test concept-test survey-prescreen pricing-probe; do
+for s in althing focus-group name-test concept-test survey-prescreen pricing-probe; do
curl -fsSL $SP_RAW/skills/$s/SKILL.md \
-o ~/.claude/skills/$s/SKILL.md
done
@@ -106,49 +106,49 @@ done
### 3. Hermes Agent (skills-compatible host)
Hermes consumes the same SKILL.md format (Agent Skills Discovery,
-agentskills.io). The `synthpanel` director skill carries Hermes-specific
+agentskills.io). The `althing` director skill carries Hermes-specific
frontmatter (`metadata.hermes.tags`, `metadata.hermes.config`,
`required_environment_variables`) so it installs and configures
cleanly:
```bash
-SP_RAW=https://raw.githubusercontent.com/DataViking-Tech/SynthPanel/main
+SP_RAW=https://raw.githubusercontent.com/DataViking-Tech/Althing/main
HERMES_SKILLS=~/.hermes/skills # adjust to your Hermes install path
-mkdir -p $HERMES_SKILLS/synthpanel $HERMES_SKILLS/focus-group \
+mkdir -p $HERMES_SKILLS/althing $HERMES_SKILLS/focus-group \
$HERMES_SKILLS/name-test $HERMES_SKILLS/concept-test \
$HERMES_SKILLS/survey-prescreen $HERMES_SKILLS/pricing-probe
-for s in synthpanel focus-group name-test concept-test survey-prescreen pricing-probe; do
+for s in althing focus-group name-test concept-test survey-prescreen pricing-probe; do
curl -fsSL $SP_RAW/skills/$s/SKILL.md \
-o $HERMES_SKILLS/$s/SKILL.md
done
```
Hermes will prompt for the configured environment variables (Anthropic /
-OpenAI / Google / xAI keys) on first activation, then route SynthPanel
+OpenAI / Google / xAI keys) on first activation, then route Althing
triggers ("run a synthetic panel", "test positioning", "compare names",
-"pricing probe", "poll 30 personas") to the `synthpanel` director,
+"pricing probe", "poll 30 personas") to the `althing` director,
which in turn delegates to the matching workflow skill. Also configure
the [MCP server](mcp.md#editor-configuration) so the tools resolve.
The index of skills is also published at
-[`/.well-known/agent-skills/index.json`](https://synthpanel.dev/.well-known/agent-skills/index.json)
-on synthpanel.dev, per Agent Skills Discovery RFC v0.2.0, so
+[`/.well-known/agent-skills/index.json`](https://althing.dev/.well-known/agent-skills/index.json)
+on althing.dev, per Agent Skills Discovery RFC v0.2.0, so
discovery-aware hosts can find them without prior knowledge.
### 4. Other MCP hosts (Cursor, Windsurf, Copilot, etc.)
-`/synthpanel-poll` is Claude Code-specific. On other hosts:
+`/althing-poll` is Claude Code-specific. On other hosts:
- Configure the [MCP server](mcp.md#editor-configuration) so the host
- can call the synthpanel tools (`run_panel`, `run_quick_poll`,
+ can call the althing tools (`run_panel`, `run_quick_poll`,
`run_prompt`, etc.) directly.
- For hosts that consume SKILL.md (Hermes, Codex CLI, Cursor, Goose,
- OpenHands, OpenCode, …), drop the `skills/synthpanel` directory plus
+ OpenHands, OpenCode, …), drop the `skills/althing` directory plus
the workflow skills into that host's skills path.
- For hosts that don't consume SKILL.md, treat the contents of
- `commands/synthpanel-poll.md` and each `skills/*/SKILL.md` as
+ `commands/althing-poll.md` and each `skills/*/SKILL.md` as
**prompt templates** — paste the workflow body into the host's chat
or your own prompt library and let the agent follow it manually.
@@ -160,11 +160,11 @@ slash-command/skill packaging is host-specific.
After installing, in a Claude Code session:
```
-/synthpanel-poll "Should we name this thing 'Traitprint' or 'Personagram'?"
+/althing-poll "Should we name this thing 'Traitprint' or 'Personagram'?"
```
Claude Code routes the slash command, which calls
-`mcp__synth_panel__run_quick_poll`, which calls the synthpanel MCP
+`mcp__althing__run_quick_poll`, which calls the althing MCP
server. If the MCP server is misconfigured you'll get a tool-call
error pointing at the missing piece (typically a missing API key —
see [Sampling Mode](mcp.md#sampling-mode) for the zero-config
@@ -179,9 +179,9 @@ auto-complete.
## Updating
-When synthpanel ships a new version of a skill or slash command:
+When althing ships a new version of a skill or slash command:
-- **Plugin install:** re-run `/plugin install synthpanel` (or
+- **Plugin install:** re-run `/plugin install althing` (or
whatever Claude Code's plugin-update flow is at that time).
- **Manual copy:** repeat the copy step from §2 above. Files
overwrite cleanly.
@@ -195,10 +195,10 @@ works as long as the named MCP tools still exist.
- [MCP server reference](mcp.md) — server config, tool list, sampling
mode.
-- [`commands/synthpanel-poll.md`](../commands/synthpanel-poll.md) —
+- [`commands/althing-poll.md`](../commands/althing-poll.md) —
the actual slash command source.
-- [`skills/synthpanel/SKILL.md`](../skills/synthpanel/SKILL.md) — the
+- [`skills/althing/SKILL.md`](../skills/althing/SKILL.md) — the
top-level director skill (Hermes-compatible).
- [`skills/`](../skills/) — the five workflow skills.
- [`.claude-plugin/plugin.json`](../.claude-plugin/plugin.json) —
- what `/plugin install synthpanel` registers.
+ what `/plugin install althing` registers.
diff --git a/docs/ai-engineer-readiness.md b/docs/ai-engineer-readiness.md
index 39288b7a..127b4669 100644
--- a/docs/ai-engineer-readiness.md
+++ b/docs/ai-engineer-readiness.md
@@ -1,9 +1,9 @@
-# SynthPanel — AI Engineer Miami Readiness Assessment
+# Althing — AI Engineer Miami Readiness Assessment
-**Author:** cpo (synthpanel)
+**Author:** cpo (althing)
**Date:** 2026-04-19
**Subject:** Pre-spotlight readiness for tonight's AI Engineer Miami demo
-**Version assessed:** synthpanel v0.9.3 (live on PyPI, site https://synthpanel.dev HTTP 200)
+**Version assessed:** althing v0.9.3 (live on PyPI, site https://althing.dev HTTP 200)
---
@@ -19,7 +19,7 @@ not for anything missing from the product itself.
- ✅ MCP sampling fallback (`sp-6at`) — zero-config demo is real
- ✅ 8 agent-framework examples live (OpenAI Agents, LangChain/LangGraph, CrewAI, LlamaIndex, MS Agent Framework, n8n, plus 2 Composio flavors)
- ✅ awesome-mcp-servers PR #4930 pending — can reference it ("we're getting listed upstream")
-- ⚠️ CLI ergonomic gotcha: `--model` must precede the subcommand (`synthpanel --model sonnet prompt …`). Trivial, but it will trip the founder live if they type it the other way.
+- ⚠️ CLI ergonomic gotcha: `--model` must precede the subcommand (`althing --model sonnet prompt …`). Trivial, but it will trip the founder live if they type it the other way.
- ✅ Framework-count drift resolved (sp-dub): README table and `examples/integrations/` both list **8 framework entries** (6 MCP-native + 2 Composio bridges). Founder's script, README, and directory now agree on "eight agent frameworks." Cite that number on stage.
---
@@ -31,8 +31,8 @@ audience. The people at Miami are building agents, evaluating MCP servers,
fighting eval infrastructure, and picking tools they can drop into a
CrewAI/LangGraph/Agents-SDK pipeline by Monday. What resonates:
-1. **"Works with my stack without a SynthPanel-specific SDK."** The fact
- that the integration is just "point your MCP client at `synthpanel
+1. **"Works with my stack without a Althing-specific SDK."** The fact
+ that the integration is just "point your MCP client at `althing
mcp-serve`" is the whole pitch. Every framework-specific wrapper they've
had to maintain has been a tax; MCP is the escape hatch.
2. **Zero-config via MCP sampling.** "No API key needed if your host
@@ -56,9 +56,9 @@ CrewAI/LangGraph/Agents-SDK pipeline by Monday. What resonates:
## 3. Gap analysis
### Installable in under 60 seconds?
-Yes. `pip install synthpanel[mcp]` → set one provider key → `synthpanel
+Yes. `pip install althing[mcp]` → set one provider key → `althing
mcp-serve` is the happy path. Docker path (`docker run ghcr.io/dataviking-
-tech/synthpanel …`) is live as a fallback.
+tech/althing …`) is live as a fallback.
### Is the MCP story clear?
Mostly yes, but **the sampling fallback is the sharpest message and it's
@@ -73,7 +73,7 @@ flip the fold.
- **No API key in at least one development environment I tried** — I could
not dogfood the survey below without one. If a founder's own CPO agent
- can't run `synthpanel prompt` without extra setup, the conference
+ can't run `althing prompt` without extra setup, the conference
hands-on booth should have at minimum a pre-seeded `.env` sample or a
one-liner that explicitly demonstrates the **no-key sampling path** via
Claude Code as host. The sampling story is the answer to this friction;
@@ -81,7 +81,7 @@ flip the fold.
- **CLI flag ordering (`--model` before the subcommand)** is unusual
argparse behavior and will bite on stage. Either switch to a subcommand-
local `--model` (ideal), or bake the model into the demo alias so the
- founder types `synthpanel demo` instead of an argparse puzzle. Do not
+ founder types `althing demo` instead of an argparse puzzle. Do not
leave this to live typing.
- **"Works with X" matrix needs a live link on the landing page** if it
is not already there. Engineers at Miami will ask "does it work with
@@ -100,7 +100,7 @@ flip the fold.
## 4. Synthetic survey — dogfood result
-**Transparency note:** I attempted to run the requested `synthpanel
+**Transparency note:** I attempted to run the requested `althing
prompt` with a simulated AI-engineer persona. My crew environment has no
`ANTHROPIC_API_KEY` (or any other provider key) configured, so the live
CLI call errored with `Missing API key: set ANTHROPIC_API_KEY`. **This is
@@ -125,7 +125,7 @@ agents with LangGraph:**
> "Honestly, the MCP angle is what gets me off the fence. I've been
> burned twice by research tools that ship a bespoke Python SDK I have
> to pin and wrap. If I can point my existing `MultiServerMCPClient` at
-> `synthpanel mcp-serve` and get structured persona output with cost
+> `althing mcp-serve` and get structured persona output with cost
> tracking, yes — I'd try it next week. My one hesitation: I want to see
> the cost-per-turn telemetry before I commit it to a workflow my PM can
> trigger."
@@ -158,7 +158,7 @@ All three are gaps that can be closed tonight.
## 5. Recommended 3-minute demo script
Everything below assumes a laptop with Claude Code installed, no
-provider key set, and synthpanel v0.9.3 already `pip install`ed. Total
+provider key set, and althing v0.9.3 already `pip install`ed. Total
walk is ~180 seconds with 15s of buffer.
### 0:00 – 0:20 — Cold open, land the hook
@@ -166,7 +166,7 @@ walk is ~180 seconds with 15s of buffer.
> three minutes. No API key on this laptop. Watch."
Open a terminal with Claude Code running as the MCP host. Have
-`synthpanel mcp-serve` registered. Say out loud: "Claude, use synthpanel
+`althing mcp-serve` registered. Say out loud: "Claude, use althing
to run a quick poll of three AI engineers: 'would you try an MCP server
for synthetic focus groups?'"
@@ -187,8 +187,8 @@ forcing. You get JSON, not vibes."*
Open `examples/integrations/openai_agents.py` in a second pane (or the
web page if it renders better). Scroll — do not read. Say:
-> "Eight agent frameworks, one MCP server. No SynthPanel-specific SDK.
-> If your framework speaks MCP, you already have a SynthPanel adapter."
+> "Eight agent frameworks, one MCP server. No Althing-specific SDK.
+> If your framework speaks MCP, you already have a Althing adapter."
Highlight the shortest example (OpenAI Agents SDK is ~20 lines). Call
out that the same server hosts `run_panel`, `extend_panel`, persona
@@ -197,7 +197,7 @@ packs, and v3 branching DAGs.
### 2:00 – 2:40 — v3 branching as the "but can it do real research?" beat
Run:
```
-synthpanel instruments graph pricing-discovery --format mermaid
+althing instruments graph pricing-discovery --format mermaid
```
Show the Mermaid DAG. One sentence: *"This is a branching instrument —
the router picks the next round based on what the panel said. It's
@@ -207,11 +207,11 @@ This closes the "is this a toy?" question without labouring the point.
### 2:40 – 3:00 — Close
Three beats, one each:
-1. `pip install synthpanel[mcp]`
+1. `pip install althing[mcp]`
2. Docker image on GHCR for zero-Python installs
3. Landing page + awesome-mcp-servers PR pending
-End with: *"synthpanel.dev. Try it with the host you're already using.
+End with: *"althing.dev. Try it with the host you're already using.
If it doesn't work with your stack, I want to hear about it at the
booth."*
@@ -219,13 +219,13 @@ booth."*
## What to fix in the next hour if possible (ordered by ROI)
-1. **Alias `synthpanel demo`** to a pre-flagged prompt that uses
+1. **Alias `althing demo`** to a pre-flagged prompt that uses
sampling + the most visually-impressive pack. Avoids live argparse
typos.
2. **Promote the sampling-fallback line** to the first paragraph of the
README and the landing hero. It is the strongest differentiator we
have and it's currently under-sold.
-3. **Pin a terminal window** with `synthpanel mcp-serve` already running
+3. **Pin a terminal window** with `althing mcp-serve` already running
inside Claude Code before walking on stage. Avoid cold-start risk.
4. **Have the `examples/integrations/` directory open** in a second tab
so any follow-up question ("does it work with LangGraph?") is a
@@ -240,7 +240,7 @@ booth."*
- **API-key demo-fail risk:** if any part of the script falls back to a
direct CLI call instead of MCP-sampling and the laptop doesn't have
- a key set, the demo dies. Mitigation: the aliased `synthpanel demo`
+ a key set, the demo dies. Mitigation: the aliased `althing demo`
above should force the MCP-sampling path, not a direct provider call.
- ~~**Framework-integration claim drift:**~~ **Resolved (sp-dub):** README
table, `examples/integrations/` directory, and founder's script all
diff --git a/docs/architecture/dispatch-symmetry-anti-pattern.md b/docs/architecture/dispatch-symmetry-anti-pattern.md
index 88d27f11..0ee31bf4 100644
--- a/docs/architecture/dispatch-symmetry-anti-pattern.md
+++ b/docs/architecture/dispatch-symmetry-anti-pattern.md
@@ -3,9 +3,9 @@
**Status:** active
-**Authors:** midgard mayor (drafted), jotunheim mayor (PR via synthpanel), yggdrasil mayor (cross-coverage)
+**Authors:** midgard mayor (drafted), jotunheim mayor (PR via althing), yggdrasil mayor (cross-coverage)
-**Empirical anchor:** 7 instances cataloged 2026-05-09 / 2026-05-10 across boardroom, dataviking-infra, synthpanel, traitprint_cloud, dataviking-site (see Inventory below).
+**Empirical anchor:** 7 instances cataloged 2026-05-09 / 2026-05-10 across boardroom, dataviking-infra, althing, traitprint_cloud, dataviking-site (see Inventory below).
## TL;DR
@@ -41,25 +41,25 @@ No exception is raised. No 500. No log line saying "feature X disabled here." Ju
### Cache-Control across DV properties (dvi-25f)
-Same pattern, repo-wide: boardroom Worker, mtg-api Worker, dataviking-site (CF Pages), mtg-frontend (CF Pages), synthpanel.dev (CF Pages) — every one had a different combination of missing Cache-Control on HTML, wrong directive on hashed assets, or wrong duration on unhashed assets. Different surface, identical root: nobody was thinking about cache headers as a property of the dispatch surface, only of the immediate response.
+Same pattern, repo-wide: boardroom Worker, mtg-api Worker, dataviking-site (CF Pages), mtg-frontend (CF Pages), althing.dev (CF Pages) — every one had a different combination of missing Cache-Control on HTML, wrong directive on hashed assets, or wrong duration on unhashed assets. Different surface, identical root: nobody was thinking about cache headers as a property of the dispatch surface, only of the immediate response.
-### Image content blocks via OpenRouter→Anthropic (synthpanel hq-m333)
+### Image content blocks via OpenRouter→Anthropic (althing hq-m333)
-synthpanel emits Anthropic-shaped `image` content blocks. Direct Anthropic API receives and renders them. OpenRouter route to the same Anthropic models: image blocks are dropped at the proxy layer, model receives only text. **Persona output silently fabricated visual reasoning** ("squints at imaginary screen") instead of refusing. 100% delivery failure masked by persona roleplay until a deterministic probe with explicit "say NO IMAGE RECEIVED if you can't see it" instruction made it visible.
+althing emits Anthropic-shaped `image` content blocks. Direct Anthropic API receives and renders them. OpenRouter route to the same Anthropic models: image blocks are dropped at the proxy layer, model receives only text. **Persona output silently fabricated visual reasoning** ("squints at imaginary screen") instead of refusing. 100% delivery failure masked by persona roleplay until a deterministic probe with explicit "say NO IMAGE RECEIVED if you can't see it" instruction made it visible.
-### `html` attachments via MCP (synthpanel hq-aaca)
+### `html` attachments via MCP (althing hq-aaca)
CLI path renders html attachments correctly into the user message. MCP path: ~50% of personas saw the html, ~50% said "you didn't attach anything." Same instrument YAML, different dispatch path, different delivery rate. Inconsistent rather than zero — even worse to debug.
-### Attachment resolver in v1 single-round (synthpanel hq-ilke)
+### Attachment resolver in v1 single-round (althing hq-ilke)
v3 multi-round path resolves bank-ref attachments before sending to the model. v1 single-round path silently drops them. v1 callers got an attachment-less response with no error.
-### Multi-round termination via MCP (synthpanel hq-fjdx)
+### Multi-round termination via MCP (althing hq-fjdx)
CLI v3 multi-round runs all N rounds. MCP v3 multi-round terminates after round 1 and falls through positionally on the rest. Caller gets an "ensemble complete" event and a partial result; never sees the rest of the rounds attempted.
-### `fetch_mode: screenshot` without playwright (synthpanel hq-gjh7)
+### `fetch_mode: screenshot` without playwright (althing hq-gjh7)
When an instrument requests `fetch_mode: screenshot` but playwright extras aren't installed, the URL fetch silently degrades to `html_text` mode instead of failing loudly. Caller gets text where they specified pixels; no warning surfaces in the run log.
@@ -92,7 +92,7 @@ The pattern that's worked best across these 7 instances is a CI test class: **fo
Examples:
```python
-# synthpanel hq-83ye: dispatch-path symmetry for multi-round v3
+# althing hq-83ye: dispatch-path symmetry for multi-round v3
@pytest.mark.parametrize("dispatcher", [cli_dispatcher, mcp_dispatcher])
def test_v3_multi_round_runs_all_rounds(dispatcher):
instrument = load_fixture("five_round_v3.yaml")
@@ -150,5 +150,5 @@ What's missing isn't *more* tests; it's *parametrized-over-dispatchers* tests, p
- `feedback_sibling_merge_cascade` (cross-town mayor memory) — the merge-time analog: code paths that touched shared files re-conflicting under parallel polecat execution. Different mechanism, same systemic shape.
- `docs/cache-control-policy.md` (dataviking-infra) — the cross-property cache policy that fell out of dvi-25f.
-- `docs/known-patterns/openrouter-byok-visual-review.md` (synthpanel) — empirical workaround for the OR→Anthropic image-block drop while hq-m333 was still open.
-- synthpanel `hq-83ye` — the first CI symmetry test of this kind in the org; reference implementation for follow-on coverage.
+- `docs/known-patterns/openrouter-byok-visual-review.md` (althing) — empirical workaround for the OR→Anthropic image-block drop while hq-m333 was still open.
+- althing `hq-83ye` — the first CI symmetry test of this kind in the org; reference implementation for follow-on coverage.
diff --git a/docs/blog/synthpanel-vs-commercial-alternatives.md b/docs/blog/althing-vs-commercial-alternatives.md
similarity index 86%
rename from docs/blog/synthpanel-vs-commercial-alternatives.md
rename to docs/blog/althing-vs-commercial-alternatives.md
index ea8aea87..efee1591 100644
--- a/docs/blog/synthpanel-vs-commercial-alternatives.md
+++ b/docs/blog/althing-vs-commercial-alternatives.md
@@ -1,11 +1,11 @@
-# SynthPanel vs Synthetic Users vs FocusPanel.ai — When Open-Source MCP Beats the SaaS
+# Althing vs Synthetic Users vs FocusPanel.ai — When Open-Source MCP Beats the SaaS
*Published 2026-04-15 · Updated 2026-07-16 · ~7 min read*
-> **TL;DR — SynthPanel is the open-source, LLM-agnostic alternative to commercial
+> **TL;DR — Althing is the open-source, LLM-agnostic alternative to commercial
> synthetic-respondent tools like Synthetic Users, FocusPanel.ai, Delve.ai, and
> POPJAM. It runs as both a CLI and a 12-tool MCP server you can drop into Claude
-> Code, Cursor, Windsurf, or Zed. Install with `pip install synthpanel[mcp]`.
+> Code, Cursor, Windsurf, or Zed. Install with `pip install althing[mcp]`.
> MIT-licensed. Its 3-model ensemble leads the SynthBench leaderboard at
> SPS 0.86–0.88 (opinionsqa 0.877, subpop 0.858; leaderboard generated
> 2026-07-17 — numbers move as the board recomputes).**
@@ -46,11 +46,11 @@ following are true:
- You want an AI coding agent to *invoke* the research panel, not you.
That's where an open-source, LLM-agnostic synthetic focus group tool starts to
-matter. Enter **SynthPanel**.
+matter. Enter **Althing**.
## 2. Why LLM-Agnostic Matters
-SynthPanel is a pure Python library with a provider-agnostic LLM client. You
+Althing is a pure Python library with a provider-agnostic LLM client. You
set an environment variable, you pick a model alias (`sonnet`, `haiku`,
`gemini`, `grok-3`, any OpenAI-compatible endpoint), and every panelist is
interviewed against that model. You can switch providers by flipping one flag.
@@ -62,7 +62,7 @@ Three things fall out of LLM-agnosticism for free:
**BYOK — bring your own key.** The cost of a 30-persona panel with a 12-question
instrument is whatever your provider charges, no markup, no seat license, no
per-panel metering. If you have a Claude enterprise deal, use it. If you have
-Gemini free-tier credits, use those. Token accounting is built in: SynthPanel
+Gemini free-tier credits, use those. Token accounting is built in: Althing
tracks input, output, cache-read, and cache-write tokens separately and emits
a per-panel cost total. What you see is what your provider actually charged.
@@ -75,13 +75,13 @@ give you this — they *are* the vendor.
**Honest model comparison.** Run the same instrument through Claude Sonnet 4.6,
GPT-4o, and Gemini 2.5 Flash, blend at `--models sonnet:0.34,gpt-4o:0.33,gemini:0.33`,
and the framework emits per-model distributions *and* the weighted ensemble.
-This is how SynthPanel tops the SynthBench leaderboard: the blended ensemble
+This is how Althing tops the SynthBench leaderboard: the blended ensemble
beats every single model on each dataset — by roughly 0.03–0.05 SPS — which
you cannot get from any single model alone.
## 3. Why YAML Instruments Matter
-Here is a SynthPanel instrument:
+Here is a Althing instrument:
```yaml
instrument:
@@ -111,7 +111,7 @@ Four facts fall out of that snippet:
`equals`, `matches`) against synthesizer-emitted fields like `themes` and
`sentiment`. Follow-up rounds are authored once and routed automatically
per-panelist. No platform UI required, no click-through to reconfigure.
-4. **It is portable.** Bundle an instrument as a "pack" (SynthPanel ships five
+4. **It is portable.** Bundle an instrument as a "pack" (Althing ships five
— `pricing-discovery`, `feature-evaluation`, `churn-exit`, `messaging-test`,
`onboarding-friction`), install it like a library, and every consumer of
that pack runs the *exact same* discussion guide.
@@ -119,7 +119,7 @@ Four facts fall out of that snippet:
Closed SaaS competitors typically expose a form-based editor. That editor is
great for non-technical teams composing one-off studies. It is terrible for
research-ops teams who want a reproducible, diffable, versionable artifact.
-That is the gap SynthPanel's YAML-instrument format fills.
+That is the gap Althing's YAML-instrument format fills.
## 4. Why MCP Matters — The Agent-Era Workflow
@@ -127,7 +127,7 @@ The Model Context Protocol (MCP) is Anthropic's standard for giving AI coding
assistants tool access. An MCP server exposes tools over stdio; any
MCP-compatible editor (Claude Code, Cursor, Windsurf, Zed) can call them.
-SynthPanel ships an MCP server with twelve tools:
+Althing ships an MCP server with twelve tools:
- `run_prompt` — one-shot LLM call against any configured model.
- `run_panel` — full synthetic focus group, including v3 branching.
@@ -142,8 +142,8 @@ Drop this JSON into your editor config:
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -160,12 +160,12 @@ respondent SaaS products cannot natively participate in it — they are not
MCP servers, they are dashboards.
If you came here searching for "MCP server survey research" or "MCP server
-focus group," SynthPanel is the thing you want to install.
+focus group," Althing is the thing you want to install.
## 5. Honest Limits (Read This Before You Publish Findings)
Synthetic research is useful for exploration, hypothesis generation, and rapid
-iteration. It is not a replacement for talking to real humans. SynthPanel
+iteration. It is not a replacement for talking to real humans. Althing
documents four known limits in its README, and they apply to every tool in
this category — commercial or otherwise:
@@ -190,19 +190,19 @@ findings with real participants before you publish, launch, or sell.
## 6. Quantitative Proof: SynthBench SPS 0.86–0.88
-Claims are cheap. SynthPanel publishes head-to-head results on
+Claims are cheap. Althing publishes head-to-head results on
[SynthBench](https://synthbench.org), an open, reproducible benchmark for
synthetic-respondent quality. Its data and scoring code are public — though,
in the interest of full disclosure, SynthBench is a sibling DataViking project
-operated by the SynthPanel maintainers, not an independent third party.
+operated by the Althing maintainers, not an independent third party.
SynthBench computes a **Synthetic-Parity Score (SPS)** — how closely a
synthetic panel's response distribution matches a real-human control group on
the same instrument.
-A 3-model ensemble of SynthPanel personas — the leaderboard's "SynthPanel
+A 3-model ensemble of Althing personas — the leaderboard's "Althing
Ensemble (3-model)" entry, an equal-weight blend of Claude Haiku 4.5,
Gemini 2.5 Flash Lite, and GPT-4o-mini, run via
-`synthpanel panel run --models haiku:0.33,gemini-flash-lite:0.33,gpt-4o-mini:0.34 --blend`
+`althing panel run --models haiku:0.33,gemini-flash-lite:0.33,gpt-4o-mini:0.34 --blend`
— leads the current SynthBench leaderboard (generated 2026-07-17) at
**SPS 0.877** on opinionsqa and **0.858** on subpop (0.813 on
globalopinionqa). That is roughly 0.03–0.05 above the best single model on
@@ -218,26 +218,26 @@ whoever wins on the leaderboard wins on the leaderboard.
If you need an **open-source synthetic focus group** tool, a **LLM-agnostic
focus group tool**, an **open-source AI persona survey** runner, or an
-**MCP server for survey research** — SynthPanel is one `pip` away.
+**MCP server for survey research** — Althing is one `pip` away.
```bash
# Full install with MCP server support
-pip install synthpanel[mcp]
+pip install althing[mcp]
# Set a provider key (any of these works)
export ANTHROPIC_API_KEY=sk-...
# Run a panel from a bundled instrument
-synthpanel panel run --personas examples/personas.yaml --instrument pricing-discovery --var problem="choosing a project management tool"
+althing panel run --personas examples/personas.yaml --instrument pricing-discovery --var problem="choosing a project management tool"
# Or start the MCP server for your AI coding agent
-synthpanel mcp-serve
+althing mcp-serve
```
-Homepage: [synthpanel.dev](https://synthpanel.dev) · Repo:
-[github.com/DataViking-Tech/SynthPanel](https://github.com/DataViking-Tech/SynthPanel)
+Homepage: [althing.dev](https://althing.dev) · Repo:
+[github.com/DataViking-Tech/Althing](https://github.com/DataViking-Tech/Althing)
· Benchmark: [synthbench.org](https://synthbench.org) · Full MCP docs:
-[synthpanel.dev/docs/mcp](https://github.com/DataViking-Tech/SynthPanel/blob/main/docs/mcp.md).
+[althing.dev/docs/mcp](https://github.com/DataViking-Tech/Althing/blob/main/docs/mcp.md).
MIT-licensed. BYOK. No dashboard. No seat license. No platform lock-in. Your
research harness, in your editor, talking to any model you want to pay for.
diff --git a/docs/brand.md b/docs/brand.md
index 354c57a9..7d393484 100644
--- a/docs/brand.md
+++ b/docs/brand.md
@@ -1,13 +1,13 @@
-# Brand notes (synthpanel)
+# Brand notes (althing)
-This file documents the brand decisions for synthpanel.dev as part of the
+This file documents the brand decisions for althing.dev as part of the
cross-property unification effort tracked under `hq-4ae`. The canonical
brand reference for the DataViking property family lives in the
dataviking-site repo.
## Family vs. product identity
-synthpanel is part of the **DataViking** property family alongside
+althing is part of the **DataViking** property family alongside
`dataviking.tech` (canonical brand reference) and `mtg-frontend`. The goal
is **family resemblance without sacrificing per-product identity** —
visitors should recognize a shared parent without the products feeling
@@ -25,7 +25,7 @@ typography, which deliberately differ across properties.
## Accent decision: retain terminal-green/teal
-synthpanel retains its **terminal-green/teal accent** (`emerald-400`,
+althing retains its **terminal-green/teal accent** (`emerald-400`,
`#34d399`) rather than migrating to the dataviking-site gold/amber. The
rationale, per the `hq-4ae` umbrella bead:
@@ -41,7 +41,7 @@ The unification work in this branch delivers exactly those "other means"
| --------------- | ------------- | -------------------------------------------- |
| dataviking.tech | gold / amber | canonical brand reference |
| mtg-frontend | gold (target) | re-skinning under separate brand-drift bead |
-| synthpanel | terminal-teal | terminal aesthetic, OSS dev-tool affordance |
+| althing | terminal-teal | terminal aesthetic, OSS dev-tool affordance |
If a future audit determines the accent split confuses users or weakens
the family signal, the migration path is straightforward: swap the
@@ -53,13 +53,13 @@ re-render). No structural HTML changes are needed.
The dataviking-site token-spec bead (`hq-pzy4`, re-filed as
`dataviking_site:dvs-cph`) is a soft dependency, not a hard one. The
-structural patterns synthpanel adopts from it:
+structural patterns althing adopts from it:
- **Footer column structure**: 3 nav columns + logomark column +
copyright/social row.
- **Header wordmark**: small text wordmark with back-link to the parent
property.
-- **Soft-pill button radius**: synthpanel uses `rounded-md` on CTA
+- **Soft-pill button radius**: althing uses `rounded-md` on CTA
buttons, which is close enough to the dataviking-site pill that no
change is needed at this scale. A future pass can promote this to a
shared token if the spec emits one.
@@ -72,6 +72,6 @@ structural patterns synthpanel adopts from it:
- `site/recommended-models/index.html`
- `site/docs/calibration/index.html`
- `site/docs/panel-run/index.html`
-- `site/blog/synthpanel-vs-commercial-alternatives.html`
+- `site/blog/althing-vs-commercial-alternatives.html`
All six surfaces share the same unified header and footer pattern.
diff --git a/docs/calibration.md b/docs/calibration.md
index 4ec61993..07aa6658 100644
--- a/docs/calibration.md
+++ b/docs/calibration.md
@@ -1,11 +1,11 @@
# Pack calibration
Calibration is how a persona pack proves its fit to a known human
-baseline. Run `synthpanel pack calibrate` and the result is written
+baseline. Run `althing pack calibrate` and the result is written
back into the pack YAML so the manifest is self-describing.
```
-synthpanel pack calibrate
+althing pack calibrate
--against DATASET:QUESTION # e.g. gss:HAPPY (v1 allowlist: gss, ntia)
[--n 50] # panel size
[--models MODELS] # default: panel run default
@@ -29,8 +29,8 @@ calibration:
extractor: pick_one:auto-derived
panelist_cost_usd: 0.6451
calibrated_at: 2026-04-26T14:23:00Z
- synthpanel_version: 0.11.1
- methodology_url: https://synthpanel.dev/docs/calibration
+ althing_version: 0.11.1
+ methodology_url: https://althing.dev/docs/calibration
```
## What JSD means
@@ -48,7 +48,7 @@ distribution. JSD is bounded in `[0, 1]` (using `log2`):
| > 0.50 | Effectively uncalibrated. |
JSD is computed locally via the same metric the convergence tracker
-uses (see `src/synth_panel/convergence.py`); the pack YAML is the
+uses (see `src/althing/convergence.py`); the pack YAML is the
**only** durable artifact — calibration does not phone home and is
distinct from `--submit-to-synthbench`.
@@ -87,7 +87,7 @@ relicensing concerns.
To override the allowlist for internal use:
```
-SYNTHBENCH_ALLOW_GATED=1 synthpanel pack calibrate ... --against wvs:Q1
+SYNTHBENCH_ALLOW_GATED=1 althing pack calibrate ... --against wvs:Q1
```
## Methodology
@@ -115,7 +115,7 @@ For each calibration run:
4. The model distribution is compared against the baseline's
`human_distribution` via Jensen-Shannon divergence.
5. The resulting JSD, plus provenance (extractor, models, cost,
- timestamp, synthpanel version), is merged into the pack YAML's
+ timestamp, althing version), is merged into the pack YAML's
`calibration:` list. Re-running against the same `(dataset,
question)` pair **replaces** the prior entry rather than appending,
so the list is always a clean record of one-result-per-baseline.
@@ -138,6 +138,6 @@ For each calibration run:
distribution. A low JSD on `gss:HAPPY` does not imply low JSD on a
different question — calibrate against multiple baselines if you
need broad coverage.
-- The command requires the `synthpanel[convergence]` extra (for the
+- The command requires the `althing[convergence]` extra (for the
`synthbench` baseline loader). Install with
- `pip install 'synthpanel[convergence]'` if not already present.
+ `pip install 'althing[convergence]'` if not already present.
diff --git a/docs/cloudflare-pages-setup.md b/docs/cloudflare-pages-setup.md
index 53db087b..b55ceec5 100644
--- a/docs/cloudflare-pages-setup.md
+++ b/docs/cloudflare-pages-setup.md
@@ -1,6 +1,6 @@
-# Cloudflare Pages — synthpanel.dev
+# Cloudflare Pages — althing.dev
-Operational runbook for the static landing site served at .
+Operational runbook for the static landing site served at .
## Source
@@ -30,7 +30,7 @@ Operational runbook for the static landing site served at Composio namespaces local toolkit actions as `LOCAL__`,
-> so the agent-visible slugs are e.g. `LOCAL_SYNTHPANEL_QUICK_POLL`.
+> so the agent-visible slugs are e.g. `LOCAL_ALTHING_QUICK_POLL`.
## Canonical pitch (use verbatim in forms)
@@ -51,10 +51,10 @@ The five registered actions are:
**Standard description (≤300 chars):**
-> SynthPanel exposes five research actions to your agent: quick_poll
+> Althing exposes five research actions to your agent: quick_poll
> (one question → synthesized panel findings), run_panel (multi-round
> instruments with v3 branching), and persona/instrument/result
-> discovery. Runs locally via the SynthPanel SDK. Any LLM.
+> discovery. Runs locally via the Althing SDK. Any LLM.
**Category / tags:**
@@ -62,16 +62,16 @@ The five registered actions are:
- Python · Local · Agent · LLM
**Auth model:** No Composio-hosted auth. The connector runs in-process;
-SynthPanel reads the caller's `ANTHROPIC_API_KEY` (or OpenAI, Gemini,
+Althing reads the caller's `ANTHROPIC_API_KEY` (or OpenAI, Gemini,
xAI) from the environment. Document this in the Composio listing's
"auth" section.
**Links:**
-- Site:
-- Repo:
-- PyPI:
-- Docs:
+- Site:
+- Repo:
+- PyPI:
+- Docs:
## Submission paths (two possible; try in order)
@@ -85,12 +85,12 @@ path B if asked.
1. Fork .
2. Read [`CONTRIBUTING.md`](https://github.com/ComposioHQ/composio/blob/next/CONTRIBUTING.md)
end to end. Note the directory conventions — for *providers* they use
- `packages/providers/`, but SynthPanel is a **tool**, not a provider,
+ `packages/providers/`, but Althing is a **tool**, not a provider,
so the target directory may differ. Open the PR as a draft and ask
Composio maintainers where it belongs.
3. Add a connector manifest pointing at the published PyPI package
- (`synthpanel`) and the toolkit factory
- (`synth_panel.integrations.composio:synthpanel_toolkit`). Exact
+ (`althing`) and the toolkit factory
+ (`althing.integrations.composio:althing_toolkit`). Exact
manifest shape is Composio-defined; copy the nearest existing
example in their repo for a locally-executing Python tool.
4. Include a changeset via `pnpm changeset`.
@@ -117,18 +117,18 @@ toolkits through Discord first:
4. Record the resulting listing URL below.
**Recorded listing URL:** `__ TBD — fill after approval __`
-**Composio toolkit slug:** `SYNTHPANEL`
+**Composio toolkit slug:** `ALTHING`
## Verification (do once the listing is live)
1. Fresh venv, install only `composio composio_langchain langchain
- langchain-anthropic synthpanel`.
+ langchain-anthropic althing`.
2. Export `ANTHROPIC_API_KEY` and `COMPOSIO_API_KEY`.
3. Run [`composio_langchain.py`](../examples/integrations/composio_langchain.py);
confirm the agent successfully calls `quick_poll` and returns a
synthesis recommendation.
4. Repeat with [`composio_crewai.py`](../examples/integrations/composio_crewai.py).
-5. In the Composio web UI, confirm `SYNTHPANEL` appears in the catalog
+5. In the Composio web UI, confirm `ALTHING` appears in the catalog
and the action descriptions are legible.
## Post-launch
@@ -136,7 +136,7 @@ toolkits through Discord first:
- Add a link to the live Composio listing from
[`docs/agent-integration-landscape.md`](agent-integration-landscape.md)
(section C.3) and the repo `README.md` integrations table.
-- Cross-post in the SynthPanel announcements (blog + social).
+- Cross-post in the Althing announcements (blog + social).
- Close bead `sp-2cw.3` with the recorded URLs in the close reason.
## Troubleshooting upstream Composio drift
@@ -149,7 +149,7 @@ decorator). That surface is still labelled experimental upstream. The
became unsatisfiable when upstream yanked the entire 0.5.x line —
published composio versions now jump from 0.1.x straight to 0.8.x. The
adapter's runtime check (`experimental.Toolkit` lookup in
-[`composio.py`](../src/synth_panel/integrations/composio.py)) catches
+[`composio.py`](../src/althing/integrations/composio.py)) catches
any upstream shape drift at construction time, so the loose pin trades
a brittle resolver contract for a clear runtime error message. When
Composio cuts a new major or minor release, the contract this
@@ -164,7 +164,7 @@ Use this checklist when triaging a suspected upstream-shape drift:
| `RuntimeError: experimental.Toolkit` at startup | Composio renamed or moved the experimental Toolkit factory | [Composio changelog](https://github.com/ComposioHQ/composio/releases) — search for "experimental" |
| `TypeError` from `experimental.Toolkit(...)` | Constructor signature changed (new required kwarg, removed kwarg) | Composio release notes for the version installed in your venv |
| Tool schemas missing or malformed in the agent catalog | `@toolkit.tool()` decorator semantics changed | Composio docs for "custom toolkits" |
-| `tests/test_integrations_composio.py::TestUpstreamShapeCanary` fails after a Composio bump | The end-to-end translation contract has drifted | Re-read the failing assertion; update the stub in the test file to mirror the new shape, then update [`composio.py`](../src/synth_panel/integrations/composio.py) |
+| `tests/test_integrations_composio.py::TestUpstreamShapeCanary` fails after a Composio bump | The end-to-end translation contract has drifted | Re-read the failing assertion; update the stub in the test file to mirror the new shape, then update [`composio.py`](../src/althing/integrations/composio.py) |
| Pydantic input validation errors at agent call time | Composio is passing a different argument shape to tool functions | Composio's tool-router source for the version installed |
If you confirm an upstream change is intentional and behaves correctly:
@@ -191,9 +191,9 @@ have installed, ask your user which version they have
installed (`pip show composio`) — they may be on an older release than
the floor in `pyproject.toml`.
-## Why the connector code lives inside SynthPanel
+## Why the connector code lives inside Althing
-The alternative would be a standalone `composio-synthpanel` package.
+The alternative would be a standalone `composio-althing` package.
We chose inline for three reasons:
1. The factory is ~300 lines — the version-skew risk of a separate
@@ -206,5 +206,5 @@ We chose inline for three reasons:
If Composio prefers third-party toolkits live in Composio-managed
repositories, we can lift the module verbatim into a
-`composio-synthpanel` package at that time; nothing in the current
+`composio-althing` package at that time; nothing in the current
design prevents the move.
diff --git a/docs/convergence.md b/docs/convergence.md
index 775430d4..164ec530 100644
--- a/docs/convergence.md
+++ b/docs/convergence.md
@@ -1,6 +1,6 @@
# Convergence telemetry
-At competitive-parity scales (n=500..10k), synthpanel panels spend most of
+At competitive-parity scales (n=500..10k), althing panels spend most of
their token budget producing diminishing returns. Once a response
distribution has stabilized for a given question, running more panelists
adds <2% signal for 10-20× the cost. The convergence feature exposes that
@@ -11,7 +11,7 @@ smaller representative n next time.
## TL;DR
```bash
-synthpanel panel run \
+althing panel run \
--personas my-panel.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
@@ -25,7 +25,7 @@ jq '.convergence.overall_converged_at, .convergence.auto_stopped' result.json
## How it works
-1. At startup synthpanel inspects the instrument and flags every question
+1. At startup althing inspects the instrument and flags every question
with a bounded response space — Likert (`rating`), yes/no (`answer`),
pick-one (`choice`), or any JSON Schema with an `enum` field. Free-text
questions are ignored; JSD on paraphrase noise is ill-defined.
@@ -50,7 +50,7 @@ jq '.convergence.overall_converged_at, .convergence.auto_stopped' result.json
| `--convergence-eps` | 0.02 | JSD threshold below which a question is treated as converged. |
| `--convergence-min-n` | 50 | Minimum panelists before `--auto-stop` is allowed to fire. |
| `--convergence-m` | 3 | Consecutive checks below epsilon required to declare convergence. |
-| `--convergence-baseline DATASET:Q` | off | Load a human baseline curve from synthbench and include in the report. Requires `pip install 'synthpanel[convergence]'`. |
+| `--convergence-baseline DATASET:Q` | off | Load a human baseline curve from synthbench and include in the report. Requires `pip install 'althing[convergence]'`. |
| `--calibrate-against DATASET:Q` | off | Attach a `calibration` sub-object to each tracked question with Jensen-Shannon divergence vs the published human distribution. v1 supports GSS only. **Pair explicitly with `--convergence-check-every`** — cadence is never implicit. See [Inline calibration vs a human baseline](#inline-calibration-vs-a-human-baseline). |
## Interpreting the report
@@ -131,7 +131,7 @@ panel result.
- **Bounded support required.** The target question must produce a
bounded distribution (enum / pick-one / likert). Free-text responses
cannot be calibrated because JSD on paraphrase noise is ill-defined.
-- **Inline only.** There is no `synthpanel calibrate RESULT.json`
+- **Inline only.** There is no `althing calibrate RESULT.json`
subcommand; calibration runs during the panel, not against a saved
result.
@@ -145,7 +145,7 @@ surprise you with cost on small-n runs.
```bash
# Correct: explicit cadence
-synthpanel panel run \
+althing panel run \
--personas my-panel.yaml \
--instrument general-survey \
--calibrate-against gss:HAPPY \
@@ -155,11 +155,11 @@ synthpanel panel run \
### The three extractor paths
Calibration needs a bounded distribution over the *same option strings*
-as the baseline. There are three ways synthpanel gets one:
+as the baseline. There are three ways althing gets one:
1. **Auto-derive (default for small-enum baselines).** If the baseline
has ≤5 enum options and you don't pass `--extract-schema`,
- synthpanel derives a `pick_one` extractor schema from the baseline's
+ althing derives a `pick_one` extractor schema from the baseline's
option strings and logs the derivation to stderr in sp-yaru style:
```
@@ -193,7 +193,7 @@ too happy") with decades of trend data — tight support, easy to
explain, ideal first wedge.
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument general-survey \
--calibrate-against gss:HAPPY \
@@ -295,7 +295,7 @@ conditional):
| `jsd` | float in [0, 1] | Jensen-Shannon divergence (base-2) between the panel distribution and the baseline's `human_distribution`. `0.0` = identical; `1.0` = maximum divergence *or* broken alignment (check `alignment_error`). |
| `baseline_spec` | string | The `DATASET:QUESTION` spec passed to `--calibrate-against` (e.g. `"gss:HAPPY"`). |
| `extractor` | string | Which extractor path produced the bounded distribution: `"pick_one:auto-derived"`, `"pick_one:manual"`, or `"likert:manual"`. |
-| `auto_derived` | bool | `true` when synthpanel derived the extractor schema from the baseline automatically (≤5-option enum, no `--extract-schema` supplied); `false` when you supplied the schema or authored a bounded instrument. |
+| `auto_derived` | bool | `true` when althing derived the extractor schema from the baseline automatically (≤5-option enum, no `--extract-schema` supplied); `false` when you supplied the schema or authored a bounded instrument. |
| `alignment_error` | string (conditional) | Present **only** when extractor keys and baseline keys are disjoint. Value is `" vs "`. **If this field is present, do not interpret `jsd` as a divergence signal.** |
The `calibration` sub-object is the committed wire format. Downstream
diff --git a/docs/cookbook/Synthetic_Focus_Group_With_SynthPanel.ipynb b/docs/cookbook/Synthetic_Focus_Group_With_SynthPanel.ipynb
index 1d02bd10..486aebe6 100644
--- a/docs/cookbook/Synthetic_Focus_Group_With_SynthPanel.ipynb
+++ b/docs/cookbook/Synthetic_Focus_Group_With_SynthPanel.ipynb
@@ -4,9 +4,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Run a synthetic focus group in Claude Code via the SynthPanel MCP server\n",
+ "# Run a synthetic focus group in Claude Code via the Althing MCP server\n",
"\n",
- "**SynthPanel** is an open-source (MIT) research harness that runs synthetic focus groups using AI personas. You define the people you want to hear from and the questions you want to ask, and SynthPanel runs the panel in parallel and synthesizes the findings.\n",
+ "**Althing** is an open-source (MIT) research harness that runs synthetic focus groups using AI personas. You define the people you want to hear from and the questions you want to ask, and Althing runs the panel in parallel and synthesizes the findings.\n",
"\n",
"This cookbook shows two ways to use it with Claude:\n",
"\n",
@@ -32,7 +32,7 @@
"- Python 3.10+\n",
"- An Anthropic API key exposed as the `ANTHROPIC_API_KEY` environment variable.\n",
"\n",
- "SynthPanel is LLM-agnostic — it also supports OpenAI, Gemini, and xAI — but we'll use Claude throughout this notebook. All the bundled examples below default to `claude-haiku-4-5` to keep this notebook fast and cheap (well under $0.10 end-to-end)."
+ "Althing is LLM-agnostic — it also supports OpenAI, Gemini, and xAI — but we'll use Claude throughout this notebook. All the bundled examples below default to `claude-haiku-4-5` to keep this notebook fast and cheap (well under $0.10 end-to-end)."
]
},
{
@@ -41,7 +41,7 @@
"metadata": {},
"outputs": [],
"source": [
- "%pip install --quiet 'synthpanel[mcp]'"
+ "%pip install --quiet 'althing[mcp]'"
]
},
{
@@ -62,19 +62,19 @@
"source": [
"## Part 1 — Drive a focus group from Claude Code via MCP\n",
"\n",
- "The fastest way to run a panel is to let Claude do it for you. SynthPanel ships an [MCP](https://modelcontextprotocol.io) server that exposes 12 tools — `run_prompt`, `run_panel`, `run_quick_poll`, `extend_panel`, persona and instrument pack management, and so on.\n",
+ "The fastest way to run a panel is to let Claude do it for you. Althing ships an [MCP](https://modelcontextprotocol.io) server that exposes 12 tools — `run_prompt`, `run_panel`, `run_quick_poll`, `extend_panel`, persona and instrument pack management, and so on.\n",
"\n",
"Once registered, Claude Code (or any MCP-capable client) can call these tools directly when you ask for a focus group in natural language.\n",
"\n",
"### Register the server with Claude Code\n",
"\n",
- "Add SynthPanel to your Claude Code MCP config (`~/.claude/mcp_settings.json` or the project-scoped equivalent):\n",
+ "Add Althing to your Claude Code MCP config (`~/.claude/mcp_settings.json` or the project-scoped equivalent):\n",
"\n",
"```json\n",
"{\n",
" \"mcpServers\": {\n",
- " \"synth_panel\": {\n",
- " \"command\": \"synthpanel\",\n",
+ " \"althing\": {\n",
+ " \"command\": \"althing\",\n",
" \"args\": [\"mcp-serve\"],\n",
" \"env\": {\n",
" \"ANTHROPIC_API_KEY\": \"sk-ant-...\"\n",
@@ -96,7 +96,7 @@
"\n",
"### The built-in skill\n",
"\n",
- "If you install the Claude Code plugin with `/plugin install synthpanel`, you also get a `/focus-group` slash command that wraps the common flow (define personas → pick instrument → run → interpret).\n",
+ "If you install the Claude Code plugin with `/plugin install althing`, you also get a `/focus-group` slash command that wraps the common flow (define personas → pick instrument → run → interpret).\n",
"\n",
"The rest of this notebook uses the **Python SDK** directly so you can see exactly what the MCP tools call under the hood. The two surfaces accept the same personas and instruments, and return the same result shapes."
]
@@ -116,7 +116,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from synth_panel import run_prompt\n",
+ "from althing import run_prompt\n",
"\n",
"result = run_prompt(\n",
" \"In one sentence, define a synthetic focus group.\",\n",
@@ -146,7 +146,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from synth_panel import quick_poll\n",
+ "from althing import quick_poll\n",
"\n",
"personas = [\n",
" {\n",
@@ -251,7 +251,7 @@
"source": [
"## Part 4 — A branching v3 panel that picks its own probe\n",
"\n",
- "Real focus groups rarely follow a fixed script — a skilled moderator listens to the first round of answers and decides whether to dig into pain, price, or alternatives. SynthPanel's **v3 branching instruments** let you encode that moderator logic as a small DAG: every round has optional `route_when` predicates that pick the next round based on the themes the synthesizer extracts.\n",
+ "Real focus groups rarely follow a fixed script — a skilled moderator listens to the first round of answers and decides whether to dig into pain, price, or alternatives. Althing's **v3 branching instruments** let you encode that moderator logic as a small DAG: every round has optional `route_when` predicates that pick the next round based on the themes the synthesizer extracts.\n",
"\n",
"`pricing-discovery` is one of the instrument packs bundled with the library. It starts with a broad discovery round, then routes into one of three probe rounds based on what surfaced."
]
@@ -262,7 +262,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from synth_panel import list_instruments, run_panel\n",
+ "from althing import list_instruments, run_panel\n",
"\n",
"# Inspect the bundled instrument packs.\n",
"for pack in list_instruments():\n",
@@ -319,7 +319,7 @@
"source": [
"### The final cross-round synthesis\n",
"\n",
- "After the last round runs, SynthPanel produces a *cross-round* synthesis that reasons about the arc of the conversation — not just the final answers."
+ "After the last round runs, Althing produces a *cross-round* synthesis that reasons about the arc of the conversation — not just the final answers."
]
},
{
@@ -349,19 +349,19 @@
"2. Polled three synthetic personas about a pricing question and got an aggregated writeup.\n",
"3. Ran a branching focus group where the moderator logic picked its own probe path based on what surfaced in the first round.\n",
"\n",
- "Every function you called here is also available as an MCP tool — meaning Claude Code, Cursor, Windsurf, or any MCP-capable agent can drive the exact same study with a natural-language request once you register the `synth_panel` server.\n",
+ "Every function you called here is also available as an MCP tool — meaning Claude Code, Cursor, Windsurf, or any MCP-capable agent can drive the exact same study with a natural-language request once you register the `althing` server.\n",
"\n",
"### Next steps\n",
"\n",
"- **Bring your own personas.** YAML-define them (`personas:` at the top level) and load them with `pack_id=\"...\"` or paste them inline.\n",
- "- **Author your own v3 instrument.** Three predicate ops (`contains`, `equals`, `matches`) and an `__end__` sentinel are enough to model most moderator flows. See the [instrument authoring docs](https://github.com/DataViking-Tech/SynthPanel/tree/main/docs).\n",
+ "- **Author your own v3 instrument.** Three predicate ops (`contains`, `equals`, `matches`) and an `__end__` sentinel are enough to model most moderator flows. See the [instrument authoring docs](https://github.com/DataViking-Tech/Althing/tree/main/docs).\n",
"- **Pair with real research.** Use synthetic panels to sharpen your discussion guide, then run it with humans. The synthetic pass is cheap; the human pass is where truth lives.\n",
"- **Add persona robustness.** Set `variants=5` on `run_panel` to generate perturbations of each persona and get a robustness score — useful when a stakeholder asks *\"what if you had used slightly different personas?\"*\n",
"\n",
"### Links\n",
"\n",
- "- Repo: \n",
- "- Docs: \n",
+ "- Repo: \n",
+ "- Docs: \n",
"- MCP spec: \n",
"- License: MIT"
]
diff --git a/docs/cookbook/instrument-regression-testing.md b/docs/cookbook/instrument-regression-testing.md
index 6a2d4a8f..6c8c6f71 100644
--- a/docs/cookbook/instrument-regression-testing.md
+++ b/docs/cookbook/instrument-regression-testing.md
@@ -5,7 +5,7 @@ fixed persona pack — you usually want to *lock its behavior*. If a
teammate edits a question, you want CI to flag it: "this question used to
produce a 70/30 enum split; the new wording produces 40/60. Intentional?"
-This recipe wires that up. It runs a small synthpanel run on every PR
+This recipe wires that up. It runs a small althing run on every PR
against a baseline panel result committed to the repo, computes a
statistical diff, and fails CI if any answer distribution drifts past a
threshold you choose.
@@ -117,10 +117,10 @@ Run the panel once locally with the model and temperature you want
locked in, then commit the resulting JSON:
```bash
-export SYNTH_PANEL_DATA_DIR="$PWD/.synthpanel"
+export SYNTH_PANEL_DATA_DIR="$PWD/.althing"
mkdir -p instrument-regression
-synthpanel --model haiku panel run \
+althing --model haiku panel run \
--personas instrument-regression/personas.yaml \
--instrument instrument-regression/survey.yaml \
--temperature 0.3 \
@@ -129,7 +129,7 @@ synthpanel --model haiku panel run \
# --save writes to $SYNTH_PANEL_DATA_DIR/results/result-.json
# and prints "Result saved: result-" to stderr.
result_id=$(grep -oE 'result-[0-9-]+-[a-f0-9]+' /tmp/run.log | head -1)
-cp ".synthpanel/results/${result_id}.json" instrument-regression/baseline.json
+cp ".althing/results/${result_id}.json" instrument-regression/baseline.json
git add instrument-regression/baseline.json
git commit -m "instrument-regression: lock baseline"
```
@@ -140,7 +140,7 @@ under $0.05.
## 4. The drift check
-This script is the glue. It runs `synthpanel runs diff` between the
+This script is the glue. It runs `althing runs diff` between the
committed baseline and a fresh run, then enforces thresholds on the
structured questions and reports theme drift on the free-text ones.
@@ -166,7 +166,7 @@ TEXT_THEME_DELTA = 2 # max new+dropped top themes per question
def main(baseline: Path, new_result: Path) -> int:
proc = subprocess.run(
[
- "synthpanel", "--output-format", "json",
+ "althing", "--output-format", "json",
"runs", "diff",
str(baseline), str(new_result),
],
@@ -203,11 +203,11 @@ def main(baseline: Path, new_result: Path) -> int:
print("\n\n".join(violations), file=sys.stderr)
print(
"\nIf this change is intentional, regenerate the baseline:\n"
- " synthpanel --model haiku panel run \\\n"
+ " althing --model haiku panel run \\\n"
" --personas .../personas.yaml \\\n"
" --instrument .../survey.yaml \\\n"
" --temperature 0.3 --save\n"
- " cp .synthpanel/results/.json instrument-regression/baseline.json",
+ " cp .althing/results/.json instrument-regression/baseline.json",
file=sys.stderr,
)
return 1
@@ -249,16 +249,16 @@ jobs:
with:
python-version: "3.11"
- - run: pip install synthpanel
+ - run: pip install althing
- name: Run panel against current instrument
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- SYNTH_PANEL_DATA_DIR: ${{ github.workspace }}/.synthpanel
+ SYNTH_PANEL_DATA_DIR: ${{ github.workspace }}/.althing
run: |
set -euo pipefail
mkdir -p "$SYNTH_PANEL_DATA_DIR/results"
- synthpanel --model haiku panel run \
+ althing --model haiku panel run \
--personas instrument-regression/personas.yaml \
--instrument instrument-regression/survey.yaml \
--temperature 0.3 \
@@ -332,7 +332,7 @@ LLM panels are not deterministic, but you can dampen the variance:
haiku:0.5,gemini-flash:0.5` and diff per-model. This catches drift
that's specific to one provider's update cycle.
- **Calibration as the source of truth.** If you have an external
- human dataset, use `synthpanel pack calibrate` to lock JSD against a
+ human dataset, use `althing pack calibrate` to lock JSD against a
real-world distribution rather than a synthetic baseline. The same
CI pattern applies — just diff against the calibration target
instead.
diff --git a/docs/cookbook/with-attachments.md b/docs/cookbook/with-attachments.md
index 8f8868bd..83067303 100644
--- a/docs/cookbook/with-attachments.md
+++ b/docs/cookbook/with-attachments.md
@@ -10,7 +10,7 @@ A copy-pasteable starter lives at
Run it with:
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/instruments/with-attachments.yaml
```
@@ -74,7 +74,7 @@ instrument:
`claude-haiku-4.5`, `gpt-4o-mini`, or `gemini-2.0-flash`. (`markdown` /
`html_text` modes return text and work with any model.)
- **`fetch_mode: screenshot` needs the `visual` extra.** Install with
- `pip install 'synthpanel[visual]'`, then fetch the browser once with
+ `pip install 'althing[visual]'`, then fetch the browser once with
`python -m playwright install chromium`. Without it, screenshot mode
can't render the page. Text-only modes have no extra dependency.
- **Failed URL fetches are a hard error by default (sy-550).** If a
diff --git a/docs/distribution-and-pitch.md b/docs/distribution-and-pitch.md
index 34456e2a..5c3f9f4f 100644
--- a/docs/distribution-and-pitch.md
+++ b/docs/distribution-and-pitch.md
@@ -1,6 +1,6 @@
-# SynthPanel Distribution Surfaces + DataViking Elevator Pitch
+# Althing Distribution Surfaces + DataViking Elevator Pitch
-**Author:** cpo (synthpanel)
+**Author:** cpo (althing)
**Date:** 2026-04-19
**Subject:** (1) AI-era distribution channels beyond MCP, ranked by reach-to-effort. (2) Three candidate DataViking elevator pitches, with a recommendation.
@@ -10,7 +10,7 @@
### What's already shipped (baseline)
-Through the MCP server alone, SynthPanel is reachable from: Claude
+Through the MCP server alone, Althing is reachable from: Claude
Code, Claude Desktop, Cursor, Windsurf, Zed, VS Code (1.102+), OpenAI
Agents SDK, LangChain / LangGraph, LlamaIndex, CrewAI, Microsoft Agent
Framework, n8n, and Composio. That is roughly 13 surfaces for the cost
@@ -34,7 +34,7 @@ entirely submission + listing copy.
| **VS Code MCP registry / marketplace** | 0.5d | VS Code MCP-native users | 1.102+ has auto-discovery; a marketplace listing with one-click config JSON still earns installs. |
| **Windsurf plugin store** | 0.5d | Windsurf users | Small but native-MCP audience. |
| **Zed extensions** | 0.5d | Zed's engineer-heavy userbase | Miami crowd is over-indexed on Zed. |
-| **Claude Code /plugin registry** | verify already-live `/plugin install synthpanel` (0.25d) | Claude Code users | Already shipped per CHANGELOG; confirm discoverability. |
+| **Claude Code /plugin registry** | verify already-live `/plugin install althing` (0.25d) | Claude Code users | Already shipped per CHANGELOG; confirm discoverability. |
**Total TIER 1 effort:** ~4 developer-days across one focused sprint.
This is the single most important block of work after tonight's demo.
@@ -46,14 +46,14 @@ Engineer Miami / agent-builder audience.
| Channel | Effort | Reach | Why it matters |
|---|---|---|---|
-| **Anthropic Cookbook PR** | 1-2d | Anthropic-developer inbound | A cookbook notebook showing "MCP + sampling + SynthPanel end-to-end" is the single highest-trust referral we can earn. Miami attendees grep the Cookbook. |
+| **Anthropic Cookbook PR** | 1-2d | Anthropic-developer inbound | A cookbook notebook showing "MCP + sampling + Althing end-to-end" is the single highest-trust referral we can earn. Miami attendees grep the Cookbook. |
| **OpenAI Cookbook PR** | 1-2d | OpenAI-developer inbound | Same argument, different tribe. Use the Agents SDK example we already have. |
-| **Hugging Face Space** | 1-2d | ML/AI researcher crowd | A public Space running `synthpanel mcp-serve` behind a Gradio UI turns the README into a live try-it-now link. HF has outsized reach into the research community. |
-| **ChatGPT custom GPT ("SynthPanel Research Assistant")** | 2-3d | Non-dev PMM/founder audience who live in ChatGPT | This is how we reach buyers who will never `pip install` anything. Wraps `run_quick_poll` as GPT Actions against a hosted endpoint. |
+| **Hugging Face Space** | 1-2d | ML/AI researcher crowd | A public Space running `althing mcp-serve` behind a Gradio UI turns the README into a live try-it-now link. HF has outsized reach into the research community. |
+| **ChatGPT custom GPT ("Althing Research Assistant")** | 2-3d | Non-dev PMM/founder audience who live in ChatGPT | This is how we reach buyers who will never `pip install` anything. Wraps `run_quick_poll` as GPT Actions against a hosted endpoint. |
| **GPT Store listing** | 0.5d after the GPT exists | GPT Store browse | Free distribution once the GPT is built. |
| **n8n Community Node (official)** | 2-3d | n8n operator audience | Upgrade from the workflow-JSON example we ship to an official n8n node with first-class UX. n8n's marketplace is where no-code ops people live. |
| **Zapier MCP connector** | 2-3d | Zapier's entire long tail | Zapier added MCP support in 2026; listing earns a meaningful SMB channel. |
-| **LangChain Hub template** | 1d | LangChain users | Submit a LangGraph template using the synthpanel MCP adapter. Lands in LangChain docs surface area. |
+| **LangChain Hub template** | 1d | LangChain users | Submit a LangGraph template using the althing MCP adapter. Lands in LangChain docs surface area. |
| **CrewAI community tools repo PR** | 1d | CrewAI users | Same pattern. |
| **Raycast extension** | 2-3d | Mac power-user audience | "Run a synthetic focus group from Raycast" is novel enough to get organic Twitter pickup. Low priority but high delight. |
@@ -62,7 +62,7 @@ this is one engineer's quarter.
### TIER 3 — Watch / skip
-- **Replicate** — SynthPanel is not a model; poor fit. **Skip.**
+- **Replicate** — Althing is not a model; poor fit. **Skip.**
- **Slack/Discord bots** — customer-specific. Only build if a specific
design-partner requests it. **Skip for now.**
- **Notion AI connector** — immature ecosystem, low reach. **Skip.**
@@ -77,7 +77,7 @@ this is one engineer's quarter.
- awesome-mcp-servers merge
- mcp.so and Smithery.ai listings
- VS Code + Cursor + Zed + Windsurf listings
-- `/plugin install synthpanel` verified discoverable
+- `/plugin install althing` verified discoverable
If any of these are missing when a Miami attendee searches post-talk,
they will assume we are earlier-stage than we are. Ship this block
@@ -93,7 +93,7 @@ inside seven days.
Of those three, **the Anthropic Cookbook PR is the single highest
ROI post-Miami investment.** It turns every future "how do I use MCP?"
-search into a synthpanel impression.
+search into a althing impression.
### ROI summary
@@ -136,7 +136,7 @@ From https://traitprint.com/wesley-johnson:
- **Traitprint** — represents real people. A career-identity platform
that turns a professional into a structured, durable profile ("trait
print").
-- **SynthPanel** — represents synthetic people. Personas-as-research-
+- **Althing** — represents synthetic people. Personas-as-research-
instruments for teams that need to learn fast and cheap.
- **SynthBench** — measures whether synthetic people are any good.
A benchmark comparing synthetic responses to real human data across
@@ -151,7 +151,7 @@ representations of human signal.
> DataViking Technologies builds AI-native infrastructure for
> understanding people. Traitprint captures who professionals
-> actually are — durable, structured, portable. SynthPanel runs
+> actually are — durable, structured, portable. Althing runs
> synthetic focus groups in your terminal or your agent's tool call.
> SynthBench measures whether those synthetic responses match real
> humans. Three products, one stack: we turn messy human signal into
@@ -170,7 +170,7 @@ listen; listener may need the second sentence before it clicks.
> Real user research is expensive and slow. DataViking builds the
> research stack for teams that can't afford either. Traitprint turns
-> a career into a queryable profile in minutes. SynthPanel runs a
+> a career into a queryable profile in minutes. Althing runs a
> synthetic focus group in seconds, from your terminal or any MCP
> host. SynthBench tells you how close the synthetic answers are to
> real humans. One founder, three tools — we ship the infrastructure
@@ -188,7 +188,7 @@ a stretch — Traitprint is identity, not research. Honesty risk.
### Candidate pitch 3 — "Measurable AI research, not vibes"
> The AI research industry runs on vibes. We're building the version
-> that runs on measurement. SynthPanel lets any team run synthetic
+> that runs on measurement. Althing lets any team run synthetic
> focus groups through their existing AI agent. SynthBench publishes
> an open leaderboard of how well synthetic responses match real
> human data — so you can pick the model that actually works for
@@ -226,7 +226,7 @@ Why pitch 1 wins:
> DataViking Technologies builds AI-native infrastructure for
> understanding people. **Traitprint** captures who professionals
-> really are — structured, durable, portable. **SynthPanel** runs
+> really are — structured, durable, portable. **Althing** runs
> synthetic focus groups from your terminal or any AI agent's tool
> call. **SynthBench** measures how close those synthetic responses
> are to real humans — open leaderboard, any provider. One stack:
diff --git a/docs/ensemble.md b/docs/ensemble.md
index 871510cf..1dad2e2e 100644
--- a/docs/ensemble.md
+++ b/docs/ensemble.md
@@ -15,7 +15,7 @@ assignments, and the edge cases operators have tripped on.
### 1. Weighted per-persona assignment (has `:`)
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml \
--models 'haiku:0.5,gemini-2.5-flash:0.5'
@@ -34,7 +34,7 @@ Useful for:
### 2. Ensemble (no `:`)
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml \
--models 'haiku,sonnet,gemini-2.5-flash'
diff --git a/docs/external-contributor-safety-audit-2026-04-15.md b/docs/external-contributor-safety-audit-2026-04-15.md
index 36ef6b44..1a37cbe0 100644
--- a/docs/external-contributor-safety-audit-2026-04-15.md
+++ b/docs/external-contributor-safety-audit-2026-04-15.md
@@ -1,8 +1,8 @@
# External Contributor Safety + CI/CD Threat-Model Audit
**Date:** 2026-04-15
-**Repo:** `DataViking-Tech/SynthPanel` (now **public**)
-**Auditor:** polecat `synthpanel/polecats/dag` (sp-273)
+**Repo:** `DataViking-Tech/Althing` (now **public**)
+**Auditor:** polecat `althing/polecats/dag` (sp-273)
**Trigger:** Public-flip + active PyPI Trusted Publishing → real external attack surface.
---
@@ -51,8 +51,8 @@ These require repo-admin / founder action. None are blocking, but (1) and (2) ar
for patch, OR require ≥ 1 approval (see #3) which Renovate cannot
self-provide.
8. **LOW — Verify PyPI Trusted Publisher binding matches post-rename repo.**
- Repo was renamed; confirm at pypi.org/manage/project/synthpanel/settings/publishing/
- that owner=`DataViking-Tech`, repo=`SynthPanel`, workflow=`publish.yml`,
+ Repo was renamed; confirm at pypi.org/manage/project/althing/settings/publishing/
+ that owner=`DataViking-Tech`, repo=`Althing`, workflow=`publish.yml`,
environment=`pypi`. Ditto test.pypi.org for `publish-test.yml` /
`pypi-test`. Trusted Publishing fails closed if mismatched, so this is
a correctness check, not a security hole.
@@ -153,7 +153,7 @@ depth. Regex validation still occurs after the assignment.
`https://test.pypi.org/legacy/`.
- Both environments exist on the repo (verified via `gh api`).
- **Cannot verify from a polecat:** whether the PyPI / TestPyPI side of
- the binding correctly references the post-rename repo (`SynthPanel`, not
+ the binding correctly references the post-rename repo (`Althing`, not
`synth-panel`) and the right workflow filenames. **Operator: confirm
via pypi.org + test.pypi.org management console.** (Operator follow-up #8 above.)
@@ -196,14 +196,14 @@ Cannot fix from a polecat (ruleset edit requires admin). See operator #3.
`.github/CODEOWNERS` is present:
```
-* @DataViking-Tech/synthpanel
-renovate.json @DataViking-Tech/synthpanel
+* @DataViking-Tech/althing
+renovate.json @DataViking-Tech/althing
```
Coverage check:
- `*` covers everything (workflows, `pyproject.toml`, `src/`, secrets-touching code). ✓
- `renovate.json` is explicitly scoped — redundant given `*` but harmless.
-- **Team validity** (whether `@DataViking-Tech/synthpanel` exists and has
+- **Team validity** (whether `@DataViking-Tech/althing` exists and has
write access): cannot verify from a polecat's token. Operator should
confirm from org settings. (Folded into follow-up #3.)
- **Not enforced** by branch ruleset (see §5 above).
@@ -323,15 +323,15 @@ individual beads.
```bash
gh repo view --json name,nameWithOwner,visibility,url,defaultBranchRef
-gh api repos/DataViking-Tech/SynthPanel/rulesets
-gh api repos/DataViking-Tech/SynthPanel/rulesets/14896580
-gh api repos/DataViking-Tech/SynthPanel/branches/main/protection # returns 404: uses ruleset, not legacy protection
-gh secret list --repo DataViking-Tech/SynthPanel
-gh api repos/DataViking-Tech/SynthPanel/environments
-gh api repos/DataViking-Tech/SynthPanel/code-scanning/default-setup
-gh api repos/DataViking-Tech/SynthPanel/vulnerability-alerts
-gh api repos/DataViking-Tech/SynthPanel/automated-security-fixes
-gh api repos/DataViking-Tech/SynthPanel \
+gh api repos/DataViking-Tech/Althing/rulesets
+gh api repos/DataViking-Tech/Althing/rulesets/14896580
+gh api repos/DataViking-Tech/Althing/branches/main/protection # returns 404: uses ruleset, not legacy protection
+gh secret list --repo DataViking-Tech/Althing
+gh api repos/DataViking-Tech/Althing/environments
+gh api repos/DataViking-Tech/Althing/code-scanning/default-setup
+gh api repos/DataViking-Tech/Althing/vulnerability-alerts
+gh api repos/DataViking-Tech/Althing/automated-security-fixes
+gh api repos/DataViking-Tech/Althing \
--jq '{allow_auto_merge,allow_merge_commit,allow_squash_merge,allow_rebase_merge,
delete_branch_on_merge,allow_update_branch,
squash_merge_commit_title,squash_merge_commit_message,
diff --git a/docs/mcp.md b/docs/mcp.md
index ba2f0b5a..781ef338 100644
--- a/docs/mcp.md
+++ b/docs/mcp.md
@@ -1,11 +1,11 @@
# MCP Server Reference
-synthpanel ships an [MCP](https://modelcontextprotocol.io/) server so AI agents can run synthetic focus groups as tool calls. The server uses stdio transport and defaults to the `haiku` model for cheap, fast iterative use.
+althing ships an [MCP](https://modelcontextprotocol.io/) server so AI agents can run synthetic focus groups as tool calls. The server uses stdio transport and defaults to the `haiku` model for cheap, fast iterative use.
## Starting the Server
```bash
-synthpanel mcp-serve
+althing mcp-serve
```
The server communicates over stdin/stdout using JSON-RPC (the MCP protocol). It is designed to be launched by an MCP-aware editor or agent framework.
@@ -17,16 +17,16 @@ The server communicates over stdin/stdout using JSON-RPC (the MCP protocol). It
The fastest path is the bundled installer (sy-skf, synthbench#262):
```bash
-synthpanel mcp install # writes ~/.claude.json (Claude Code)
-synthpanel mcp install --scope project # writes ./.mcp.json (checked in)
-synthpanel mcp install --host claude-desktop # platform-specific Claude Desktop config
-synthpanel mcp install --host cursor # ~/.cursor/mcp.json (--scope project → ./.cursor/mcp.json)
-synthpanel mcp install --host windsurf # ~/.codeium/windsurf/mcp_config.json
-synthpanel mcp install --host zed # ~/.config/zed/settings.json (context_servers schema)
-synthpanel mcp install --host auto # detect installed hosts, confirm each (--yes accepts all)
-synthpanel mcp install --target /path/to/mcp.json # any other host with an mcpServers map
-synthpanel mcp install --env ANTHROPIC_API_KEY=sk-... # bake credentials into the entry (optional)
-synthpanel mcp uninstall --host zed # remove exactly the entry the installer manages
+althing mcp install # writes ~/.claude.json (Claude Code)
+althing mcp install --scope project # writes ./.mcp.json (checked in)
+althing mcp install --host claude-desktop # platform-specific Claude Desktop config
+althing mcp install --host cursor # ~/.cursor/mcp.json (--scope project → ./.cursor/mcp.json)
+althing mcp install --host windsurf # ~/.codeium/windsurf/mcp_config.json
+althing mcp install --host zed # ~/.config/zed/settings.json (context_servers schema)
+althing mcp install --host auto # detect installed hosts, confirm each (--yes accepts all)
+althing mcp install --target /path/to/mcp.json # any other host with an mcpServers map
+althing mcp install --env ANTHROPIC_API_KEY=sk-... # bake credentials into the entry (optional)
+althing mcp uninstall --host zed # remove exactly the entry the installer manages
```
The command merges into the host's existing servers map (`mcpServers`,
@@ -40,14 +40,14 @@ config for an editor that isn't installed. After a real write it prints
No secret is written unless you pass `--env` explicitly: by default the
entry has no `env` block and the installer prints a note pointing at
-`synthpanel login` / provider env vars (sampling-capable hosts need no
+`althing login` / provider env vars (sampling-capable hosts need no
key at all — see [Sampling Mode](#sampling-mode)).
The installer also refuses by default when the `mcp` optional extra
isn't installed in the current Python env — without it,
-`synthpanel mcp-serve` would crash at launch time and the host would
+`althing mcp-serve` would crash at launch time and the host would
report a generic "server failed to start" with no actionable hint. The
-refusal points at the one-line fix (`pip install 'synthpanel[mcp]'`) and
+refusal points at the one-line fix (`pip install 'althing[mcp]'`) and
mentions the `--allow-missing-extra` escape hatch for cross-machine
setups where the editor and the server live in different envs (sy-xyn).
Equivalent guard runs at `mcp-serve` start so a stale host config that
@@ -60,12 +60,12 @@ so you can pipe the preview through `jq`, redirect it to a file, or feed
it back into the installer:
```bash
-synthpanel mcp install --target ~/.cursor/mcp.json --dry-run
-# stderr: Would install MCP server 'synth_panel' in /Users/you/.cursor/mcp.json.
-# stdout: { "mcpServers": { "synth_panel": { ... } } }
+althing mcp install --target ~/.cursor/mcp.json --dry-run
+# stderr: Would install MCP server 'althing' in /Users/you/.cursor/mcp.json.
+# stdout: { "mcpServers": { "althing": { ... } } }
-synthpanel mcp install --target ~/.cursor/mcp.json --dry-run 2>/dev/null \
- | jq '.mcpServers.synth_panel'
+althing mcp install --target ~/.cursor/mcp.json --dry-run 2>/dev/null \
+ | jq '.mcpServers.althing'
```
In `--output-format json` mode the entire payload (action, entry, and
@@ -77,8 +77,8 @@ If you'd rather hand-edit, the entry it produces is:
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": { "ANTHROPIC_API_KEY": "sk-..." }
}
@@ -94,10 +94,10 @@ Prefer a zero-config first run? Skip the `env` block entirely — see
### Claude Code Plugin
```
-/plugin install synthpanel
+/plugin install althing
```
-This adds the `/focus-group` skill plus the `/synthpanel-poll` slash command to your Claude Code session. The plugin auto-discovers the bundled `commands/` and `skills/` directories.
+This adds the `/focus-group` skill plus the `/althing-poll` slash command to your Claude Code session. The plugin auto-discovers the bundled `commands/` and `skills/` directories.
Prefer to install without the plugin, or use a different host? See
[Agent Skills & Slash Commands](agent-skills.md) for manual copy
@@ -111,8 +111,8 @@ fields. Add this block to your Hermes config:
```yaml
mcp_servers:
- synthpanel:
- command: "synthpanel"
+ althing:
+ command: "althing"
args: ["mcp-serve"]
timeout: 180
connect_timeout: 60
@@ -120,14 +120,14 @@ mcp_servers:
ANTHROPIC_API_KEY: "sk-..."
```
-If you don't want to install the `synthpanel` binary globally, use
+If you don't want to install the `althing` binary globally, use
[`uvx`](https://docs.astral.sh/uv/) to fetch and run it on demand:
```yaml
mcp_servers:
- synthpanel:
+ althing:
command: "uvx"
- args: ["--from", "synthpanel[mcp]", "synthpanel", "mcp-serve"]
+ args: ["--from", "althing[mcp]", "althing", "mcp-serve"]
timeout: 180
connect_timeout: 60
env:
@@ -148,7 +148,7 @@ picked up.
### Other MCP hosts
Any host that speaks the MCP stdio transport works the same way: launch
-`synthpanel mcp-serve` as a subprocess and pass provider keys through
+`althing mcp-serve` as a subprocess and pass provider keys through
the environment. The Hermes block above is the canonical shape — most
hosts map onto either that YAML form or the JSON form used by Claude
Code / Cursor / Windsurf. If your host needs an explicit transport
@@ -159,14 +159,14 @@ field, set it to `stdio`.
If you configured the MCP server manually (without `/plugin install`) you can still get all commands and skills by running:
```bash
-synthpanel install-skills
+althing install-skills
```
This copies the bundled slash commands and skills into `~/.claude/`:
| Type | Name | Installs to |
|------|------|-------------|
-| Slash command | `/synthpanel-poll` | `~/.claude/commands/synthpanel-poll.md` |
+| Slash command | `/althing-poll` | `~/.claude/commands/althing-poll.md` |
| Skill | `concept-test` | `~/.claude/skills/concept-test/SKILL.md` |
| Skill | `focus-group` | `~/.claude/skills/focus-group/SKILL.md` |
| Skill | `name-test` | `~/.claude/skills/name-test/SKILL.md` |
@@ -176,7 +176,7 @@ This copies the bundled slash commands and skills into `~/.claude/`:
For a project-scoped install (places files in `.claude/` relative to the current directory instead of `~/.claude/`):
```bash
-synthpanel install-skills --target .claude
+althing install-skills --target .claude
```
The command is idempotent — running it again overwrites existing files with the current bundled versions.
@@ -190,7 +190,7 @@ Every panel-running tool call (`run_panel`, `run_quick_poll`, `extend_panel`)
- Echoed verbatim into `panel_verdict.meta.decision_being_informed`.
- *Omitted* → v1.0.x grace: the server synthesizes
`"unspecified-legacy-call"`, returns a `W_DECISION_MISSING` nudge in
- `warnings[]`, and proceeds; under `SYNTHPANEL_SCHEMA_MIN>=1.1.0` omission
+ `warnings[]`, and proceeds; under `ALTHING_SCHEMA_MIN>=1.1.0` omission
is a hard typed `MISSING_DECISION` reject.
- Provided but empty after trim → `MISSING_DECISION`. `<12` chars →
`INVALID_TOOL_ARG`. `>280` → `DECISION_TOO_LONG`. No silent truncation.
@@ -412,7 +412,7 @@ is not retrievable later — sampling always returns full transcripts regardless
`run_panel`, `run_quick_poll`, and `extend_panel` accept an optional
**`max_cost`** argument — a hard ceiling on the run's total spend, in USD. It
is the MCP analog of the CLI's `--max-cost` and wires into the same `CostGate`
-machinery (`src/synth_panel/cost.py`): after each panelist completes,
+machinery (`src/althing/cost.py`): after each panelist completes,
`running_cost / completed_n * total_n` is compared against the ceiling.
```jsonc
@@ -505,8 +505,8 @@ execution mode** (sampling vs BYOK) and, in BYOK, **which default
model**. Both are deterministic and observable from the response payload
(`mode` and `model` fields).
-Source of truth: `decide_mode()` in `src/synth_panel/mcp/sampling.py`
-and `_resolve_mcp_default_model()` in `src/synth_panel/mcp/server.py`.
+Source of truth: `decide_mode()` in `src/althing/mcp/sampling.py`
+and `_resolve_mcp_default_model()` in `src/althing/mcp/server.py`.
### Stage 1 — execution mode
@@ -524,7 +524,7 @@ and `_resolve_mcp_default_model()` in `src/synth_panel/mcp/server.py`.
"Provider key available" means any of `ANTHROPIC_API_KEY`,
`OPENAI_API_KEY`, `XAI_API_KEY`, `GOOGLE_API_KEY`, `GEMINI_API_KEY`, or
`OPENROUTER_API_KEY` — checked first against the process environment,
-then against the on-disk credential store written by `synthpanel login`
+then against the on-disk credential store written by `althing login`
(so MCP-launched subprocesses recognise keys the CLI can see).
The auto rule "local key wins over sampling" exists so users who *have*
@@ -556,7 +556,7 @@ equivalent — today that means `openrouter/auto` →
`openrouter/anthropic/claude-haiku-4.5` (OpenRouter's auto-router can
pick a slow reasoning model, turning a 20-persona panel into a
15-minute stall). The same policy applies on all three surfaces (MCP,
-SDK, `panel run`) via the shared `synth_panel.llm.fast_default` module,
+SDK, `panel run`) via the shared `althing.llm.fast_default` module,
and each surface emits a one-line note when the swap fires. An explicit
`model="openrouter/auto"` is always honored — the swap only touches the
implicit default.
@@ -580,7 +580,7 @@ benefit from direct provider access and structured outputs.
MCP has a spec-level feature called
[**sampling**](https://modelcontextprotocol.io/specification/2025-03-26/client/sampling)
where the server can ask the invoking client to run an LLM completion
-on its behalf. synthpanel uses this to deliver a zero-configuration
+on its behalf. althing uses this to deliver a zero-configuration
first-run UX: if you haven't set a provider API key and your client
advertises `sampling`, the `run_prompt` and `run_quick_poll` tools
borrow the client's own LLM access instead of failing.
@@ -596,7 +596,7 @@ Sampling mode is intentionally less capable than BYOK:
Claude; other clients may route through whichever provider they have
configured). Cross-provider ensembles require BYOK.
- **No cost accounting.** Token usage is charged to the host agent's
- subscription; synthpanel returns `"usage": null` and `"cost": null`.
+ subscription; althing returns `"usage": null` and `"cost": null`.
- **Capped panel size.** `run_quick_poll` is limited to 3 personas in
sampling mode to protect the host agent's context window. Larger
runs require BYOK.
@@ -633,7 +633,7 @@ provider access and structured outputs.
## Host Integration Flags
-### `SYNTHPANEL_DRIFT_DEGRADE`
+### `ALTHING_DRIFT_DEGRADE`
Controls what the server returns when the structured-output engine's 3-strike
retry budget exhausts (see the `sp-d1x0` retry policy).
@@ -662,12 +662,12 @@ Set in your MCP `env` block alongside provider keys:
```json
{
"mcpServers": {
- "synth_panel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"env": {
"ANTHROPIC_API_KEY": "sk-...",
- "SYNTHPANEL_DRIFT_DEGRADE": "1"
+ "ALTHING_DRIFT_DEGRADE": "1"
}
}
}
@@ -680,10 +680,10 @@ diagram.
## Data Storage
-Panel results, persona packs, and instrument packs are stored under `~/.synthpanel/` (configurable via `SYNTH_PANEL_DATA_DIR`):
+Panel results, persona packs, and instrument packs are stored under `~/.althing/` (configurable via `SYNTH_PANEL_DATA_DIR`):
```
-~/.synthpanel/
+~/.althing/
├── persona_packs/ # Saved persona packs (YAML)
├── packs/instruments/ # Installed instrument packs (YAML)
└── results/ # Panel results (JSON) + session data
@@ -691,9 +691,9 @@ Panel results, persona packs, and instrument packs are stored under `~/.synthpan
## Troubleshooting
-### `command not found: synthpanel`
+### `command not found: althing`
-The MCP host can't see the `synthpanel` binary on its `PATH`. This is
+The MCP host can't see the `althing` binary on its `PATH`. This is
the single most common failure mode, because MCP subprocesses inherit
the host's PATH — not your shell's.
@@ -701,17 +701,17 @@ the host's PATH — not your shell's.
1. Install globally so any host can find it:
```bash
- pip install "synthpanel[mcp]" # or pipx install "synthpanel[mcp]"
- which synthpanel # confirm the binary is on PATH
+ pip install "althing[mcp]" # or pipx install "althing[mcp]"
+ which althing # confirm the binary is on PATH
```
2. Or point `command` at the absolute binary path:
```jsonc
- "command": "/Users/you/.venv/bin/synthpanel"
+ "command": "/Users/you/.venv/bin/althing"
```
3. Or run it through `uvx` so the host fetches it on demand:
```jsonc
"command": "uvx",
- "args": ["--from", "synthpanel[mcp]", "synthpanel", "mcp-serve"]
+ "args": ["--from", "althing[mcp]", "althing", "mcp-serve"]
```
Claude Desktop on macOS is particularly strict about PATH — it runs
@@ -723,15 +723,15 @@ absolute path or `uvx` for that host.
The server launched but the host isn't seeing `run_panel`,
`run_quick_poll`, etc. in the tool picker.
-- **MCP extra missing.** `pip install synthpanel` alone is not enough —
+- **MCP extra missing.** `pip install althing` alone is not enough —
the MCP server requires the SDK from the `[mcp]` extra:
```bash
- pip install "synthpanel[mcp]"
+ pip install "althing[mcp]"
```
- **Stale host cache.** Some hosts cache the tool list per server entry.
Restart the host (full quit, not just window close) after editing
config or upgrading the package.
-- **Server logs.** Run `synthpanel mcp-serve` in a terminal to confirm
+- **Server logs.** Run `althing mcp-serve` in a terminal to confirm
it boots and produces no errors before the host launches it.
### Missing or invalid API key
@@ -743,11 +743,11 @@ Symptom: tool calls return `MISSING_CREDS` or a provider-specific
the host's inherited environment). Setting `ANTHROPIC_API_KEY` in
your shell profile does **not** automatically propagate — put it in
the `env` block of the MCP server entry.
-- Run `synthpanel login` to seed the on-disk credential store; the MCP
+- Run `althing login` to seed the on-disk credential store; the MCP
server reads from there as a fallback when the env is empty (see
[Model Resolution Order](#model-resolution-order)).
- If your host advertises MCP `sampling` (Claude Desktop, Claude Code,
- Cursor, Windsurf), you can omit the key entirely and synthpanel will
+ Cursor, Windsurf), you can omit the key entirely and althing will
borrow the host's LLM access — see [Sampling Mode](#sampling-mode).
### Timeouts on long panel runs
@@ -759,7 +759,7 @@ Symptom: the host kills the subprocess mid-panel with a timeout error.
- Raise the host's per-tool timeout. For Hermes:
```yaml
mcp_servers:
- synthpanel:
+ althing:
timeout: 300 # 5 min for heavy panels
connect_timeout: 60
```
@@ -780,6 +780,6 @@ envelope. `run_prompt` does not require it.
The structured-output engine's 3-strike retry budget was exhausted.
Either re-run the tool (transient model output drift is recoverable),
-or set `SYNTHPANEL_DRIFT_DEGRADE=1` in the MCP `env` block to get a
+or set `ALTHING_DRIFT_DEGRADE=1` in the MCP `env` block to get a
degraded result with a `schema_drift` flag instead of an error — see
[Host Integration Flags](#host-integration-flags).
diff --git a/docs/methodology.md b/docs/methodology.md
index 6d13fbcb..c8929877 100644
--- a/docs/methodology.md
+++ b/docs/methodology.md
@@ -1,7 +1,7 @@
# Methodology
> **Audience:** ML and data-engineering evaluators — the inspectability buyers.
-> If you're deciding whether SynthPanel's panels are credible enough to put in
+> If you're deciding whether Althing's panels are credible enough to put in
> front of a real research decision, this page is the proof artifact.
> **Cover image (placeholder):** `convergence-decay-vs-cohort-size.png` — to
@@ -18,7 +18,7 @@ breaks — observability beats reliability in stated preference."*
So this page documents what's actually happening behind a panel call. No
marketing language, no "AI-powered representativeness." If you find a hole in
-the methodology, [open an issue](https://github.com/DataViking-Tech/SynthPanel/issues) —
+the methodology, [open an issue](https://github.com/DataViking-Tech/Althing/issues) —
that's the loop we want.
## Cohort construction
@@ -27,7 +27,7 @@ A panel run resolves three layers:
1. **Persona pack** — a YAML file or installed pack name. Each persona is a
`{name, age, occupation, background, personality_traits, ...}` record;
- bundled packs are versioned and visible in `synthpanel pack list`.
+ bundled packs are versioned and visible in `althing pack list`.
2. **Prompt template** — `templates/current.txt` by default; alternates exist
for ablation (`templates/minimal.txt`, `templates/demo.txt`,
`templates/values.txt`). The template determines which persona fields land
@@ -43,13 +43,13 @@ rules or surfaces the gap as `demographic_skew` post-run.
## Sampling
-For panels above 500, SynthPanel tracks **response-distribution
+For panels above 500, Althing tracks **response-distribution
convergence** live via Jensen-Shannon divergence per question and can
auto-stop once every bounded question (Likert / yes-no / pick-one / enum) has
stabilized.
```bash
-synthpanel panel run \
+althing panel run \
--personas large-panel.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
@@ -117,7 +117,7 @@ exposes:
resolvable via the `panel-result://` MCP resource. Nothing is summarized
away.
-The `synthpanel report` post-hoc renderer opens with a mandatory
+The `althing report` post-hoc renderer opens with a mandatory
synthetic-panel banner (and closes with a matching footer) so the output
can't be mistaken for real-user research. **Synthetic panels are for
exploration, hypothesis generation, and rapid iteration. They do not replace
diff --git a/docs/migration-v1.md b/docs/migration-v1.md
index 4e7c3ff1..2f8aee7f 100644
--- a/docs/migration-v1.md
+++ b/docs/migration-v1.md
@@ -4,7 +4,7 @@
> contract is what changes; the CLI surface is largely unchanged.
v1.0.0 freezes the MCP request/response contract. The schema lives in the
-package at [`synthpanel/schemas/v1.0.0.json`](../src/synth_panel/schemas/v1.0.0.json)
+package at [`althing/schemas/v1.0.0.json`](../src/althing/schemas/v1.0.0.json)
and is the source of truth for everything below.
## What changed
@@ -103,7 +103,7 @@ stateDiagram-v2
courtesy, not a contract — you'll lose your panel runs the day v1.1 lands if
you haven't added the field.
-## Schema-drift behavior (`SYNTHPANEL_DRIFT_DEGRADE`)
+## Schema-drift behavior (`ALTHING_DRIFT_DEGRADE`)
The structured-output engine retries malformed responses up to 3 strikes (see
the `sp-d1x0` retry policy). What happens *after* exhaustion changes between
@@ -122,7 +122,7 @@ v1.0 and v1.1.
The agent sees an error and decides — retry, fall back, surface to the user.
-### v1.0.0 with `SYNTHPANEL_DRIFT_DEGRADE=1` — opt-in beta of v1.1 behavior
+### v1.0.0 with `ALTHING_DRIFT_DEGRADE=1` — opt-in beta of v1.1 behavior
```json
{
@@ -165,7 +165,7 @@ the host-side semantics.
## Migration checklist
-For agent code that calls SynthPanel via MCP:
+For agent code that calls Althing via MCP:
- [ ] Add `decision_being_informed` to every `run_panel`, `run_quick_poll`,
and `extend_panel` call. 12–280 chars, single line.
@@ -174,13 +174,13 @@ For agent code that calls SynthPanel via MCP:
Branch on `code` + `severity`; log `extension[]` but don't branch on it.
- [ ] Update error handling to read `error_code` and `retry_safe` instead of
string-matching `message`.
-- [ ] Decide your stance on `SYNTHPANEL_DRIFT_DEGRADE`:
+- [ ] Decide your stance on `ALTHING_DRIFT_DEGRADE`:
leave it off (typed error) or flip it on now to preview v1.1.
For MCP host operators:
-- [ ] Pin to `synthpanel>=1.0,<2.0` once your callers are migrated.
-- [ ] Decide whether to set `SYNTHPANEL_DRIFT_DEGRADE=1` in the env block.
+- [ ] Pin to `althing>=1.0,<2.0` once your callers are migrated.
+- [ ] Decide whether to set `ALTHING_DRIFT_DEGRADE=1` in the env block.
Document the choice for callers.
- [ ] Plan the v1.1 cutover — the grace window closes when v1.1.0 lands.
@@ -189,4 +189,4 @@ For MCP host operators:
- Full field-by-field reference: [docs/response-contract.md](response-contract.md)
- Methodology and inspectability: [docs/methodology.md](methodology.md)
- MCP host integration: [docs/mcp.md](mcp.md)
-- Schema source: [`src/synth_panel/schemas/v1.0.0.json`](../src/synth_panel/schemas/v1.0.0.json)
+- Schema source: [`src/althing/schemas/v1.0.0.json`](../src/althing/schemas/v1.0.0.json)
diff --git a/docs/model-packs.md b/docs/model-packs.md
index c187a6a1..d0de4bf2 100644
--- a/docs/model-packs.md
+++ b/docs/model-packs.md
@@ -31,7 +31,7 @@
## Why model packs exist
-SynthPanel's [SynthBench](https://synthbench.org) leaderboard tracks model
+Althing's [SynthBench](https://synthbench.org) leaderboard tracks model
fidelity against real human distributions (GlobalOpinionQA and friends). Two
findings from the live data drive these packs:
@@ -62,7 +62,7 @@ with only male software engineers.
Each pack lists:
- **When to use it** — the decision shape the pack is calibrated for.
-- **CLI** — drop-in `synthpanel panel run` invocation.
+- **CLI** — drop-in `althing panel run` invocation.
- **MCP / SDK** — equivalent agent invocation (the `models` array passed to
the [`run_panel`](mcp.md) tool, or `persona_models=` from the
[Python SDK](../README.md#use-as-a-python-library)).
@@ -78,7 +78,7 @@ this pack is for "is this question even legible?" not "what would users do?".
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
@@ -100,7 +100,7 @@ synthpanel panel run \
```python
# Python SDK
-from synth_panel import run_panel
+from althing import run_panel
panel = run_panel(pack_id="general-consumer", instrument_pack="pricing-discovery", model="haiku")
```
@@ -120,7 +120,7 @@ panel per model.
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
@@ -158,7 +158,7 @@ more objections.
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument 'landing-page-comprehension' \
--var landing_page="Acme — ship faster with automated deploys. Start free, no card required." \
@@ -198,7 +198,7 @@ three families gets you cross-provider diversity at preflight prices.
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument 'name-test' \
--var candidates="Core, Plus, Pro" \
@@ -241,7 +241,7 @@ general-purpose models.
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas enterprise-buyer \
--instrument 'feature-prioritization' \
--var features="SSO, audit logs, and role-based access control" \
@@ -278,7 +278,7 @@ to over-index on technical detail in free-text.
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas developer \
--instrument 'feature-prioritization' \
--var features="SSO, audit logs, and role-based access control" \
@@ -306,7 +306,7 @@ per model, with blending. **This is the most expensive pack.**
**CLI:**
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
@@ -333,7 +333,7 @@ synthpanel panel run \
**What you get:** four full passes of the panel (15 personas × 4 models ×
N questions). Cost typically $1–$5 for a moderate instrument. The `blend`
block's `convergence` score is the headline signal — high convergence across
-four families is the strongest fidelity claim SynthPanel can make.
+four families is the strongest fidelity claim Althing can make.
---
diff --git a/docs/oauth-discovery.md b/docs/oauth-discovery.md
index 38b2cf86..a8226e95 100644
--- a/docs/oauth-discovery.md
+++ b/docs/oauth-discovery.md
@@ -1,6 +1,6 @@
# OAuth / OIDC Discovery — Not Applicable
-**Status:** N/A — SynthPanel publishes no `/.well-known/openid-configuration`
+**Status:** N/A — Althing publishes no `/.well-known/openid-configuration`
or `/.well-known/oauth-authorization-server` document.
**Bead:** sy-iaf (GH#416, AR-5)
@@ -17,28 +17,28 @@ The agent-ready intake task for AR-5 is conditional:
> `issuer`, `authorization_endpoint`, `token_endpoint`, `jwks_uri`,
> `grant_types_supported`.
-SynthPanel has no protected APIs to advertise. Each surface is unauthenticated
+Althing has no protected APIs to advertise. Each surface is unauthenticated
or out of scope for OAuth discovery:
| Surface | Transport | Auth model |
|---|---|---|
-| `synthpanel` CLI | local process | none — runs on the user's machine |
-| `synthpanel mcp-serve` | stdio (per Model Context Protocol) | none — bound to the spawning client |
-| [`synthpanel.dev`](https://synthpanel.dev) | static site (Cloudflare Pages) | none — public docs only |
+| `althing` CLI | local process | none — runs on the user's machine |
+| `althing mcp-serve` | stdio (per Model Context Protocol) | none — bound to the spawning client |
+| [`althing.dev`](https://althing.dev) | static site (Cloudflare Pages) | none — public docs only |
Provider credentials (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `XAI_API_KEY`,
`GOOGLE_API_KEY` / `GEMINI_API_KEY`) are user-supplied and travel directly
-from the local CLI to the upstream provider; SynthPanel itself never brokers
+from the local CLI to the upstream provider; Althing itself never brokers
an OAuth flow.
## When this should be revisited
Re-open this if any of the following ship:
-- A hosted SynthPanel API (HTTP) requiring per-user authentication.
+- A hosted Althing API (HTTP) requiring per-user authentication.
- An MCP transport other than stdio (e.g. HTTP/SSE) that fronts a
multi-tenant deployment.
-- A first-party identity provider issuing tokens for SynthPanel resources.
+- A first-party identity provider issuing tokens for Althing resources.
In those cases the discovery document(s) above become required and AR-5
graduates from N/A to a build task.
diff --git a/docs/production-operations.md b/docs/production-operations.md
index f23b8928..0b08798e 100644
--- a/docs/production-operations.md
+++ b/docs/production-operations.md
@@ -1,13 +1,13 @@
# Production Operations
-How synthpanel behaves when things go wrong, cost money, or need to be
+How althing behaves when things go wrong, cost money, or need to be
reproduced — the operational contract for running panels in CI, agent
pipelines, and other unattended environments.
Every claim on this page cites the mechanism that implements it. If the code
and this page ever disagree, the code wins — file an issue.
-> **Audience:** operators wiring `synthpanel panel run` or the MCP server
+> **Audience:** operators wiring `althing panel run` or the MCP server
> into automation. For the response *schema* (envelope fields, `flags[]`,
> the typed error object) see [docs/response-contract.md](response-contract.md);
> this page covers runtime behavior: failure, money, scale, determinism,
@@ -18,8 +18,8 @@ and this page ever disagree, the code wins — file an issue.
### Typed error envelopes (MCP)
MCP tool failures return a typed error envelope, not free text
-(`src/synth_panel/mcp/server.py`, mirrored from the v1.0.0 schema in
-`src/synth_panel/schemas/v1.0.0.json`):
+(`src/althing/mcp/server.py`, mirrored from the v1.0.0 schema in
+`src/althing/schemas/v1.0.0.json`):
```json
{
@@ -44,10 +44,10 @@ spend); response validation runs before the artifact leaves the server
### Timeouts
The MCP server enforces a per-panelist time budget of 30 seconds
-(`PANELIST_TIMEOUT` in `src/synth_panel/_runners.py`), scaled by panel
+(`PANELIST_TIMEOUT` in `src/althing/_runners.py`), scaled by panel
shape: `30s x personas x rounds` for multi-round runs, `30s x personas x
(1 + variants)` for single-round (`_panel_timeout_envelope` in
-`src/synth_panel/mcp/server.py`). Exceeding it returns a `PANEL_TIMEOUT`
+`src/althing/mcp/server.py`). Exceeding it returns a `PANEL_TIMEOUT`
envelope carrying the computed `timeout_seconds` so the caller can see the
budget it blew. Single-completion provider timeouts surface as
`MODEL_TIMEOUT`. Both are `retry_safe: true`.
@@ -56,7 +56,7 @@ budget it blew. Single-completion provider timeouts surface as
When *every* panelist fails — wholesale exception, all responses errored, or
zero tokens with nothing usable — the run raises `PanelTotalFailureError`
-(`detect_total_failure` / `run_panel_sync` in `src/synth_panel/_runners.py`)
+(`detect_total_failure` / `run_panel_sync` in `src/althing/_runners.py`)
instead of returning a normally-shaped "panel complete" result. The error
carries a structured diagnostic: the models exercised and up to 3 sample
per-persona error strings, so the banner names the actual upstream failure
@@ -65,18 +65,18 @@ per-persona error strings, so the banner names the actual upstream failure
- **CLI:** the run is marked invalid, the JSON envelope carries
`total_failure` (the diagnostic) plus a classified `abort_reason`
(`_classify_total_failure_abort_reason` in
- `src/synth_panel/cli/commands.py` — e.g. rate-limit exhaustion is tagged
+ `src/althing/cli/commands.py` — e.g. rate-limit exhaustion is tagged
distinctly so you know to raise `--rate-limit-rps` / retries instead of
chasing a model bug), and the process exits `2`.
- **MCP:** `run_panel`, `run_quick_poll`, and `extend_panel` all serialize
the same shape (`_total_failure_envelope` in
- `src/synth_panel/mcp/server.py`): `{"error": ..., "run_invalid": true,
+ `src/althing/mcp/server.py`): `{"error": ..., "run_invalid": true,
"total_failure": {...}}`.
### Exit codes and abort discipline (CLI)
-`synthpanel panel run` exit codes (end of `handle_panel_run`,
-`src/synth_panel/cli/commands.py`):
+`althing panel run` exit codes (end of `handle_panel_run`,
+`src/althing/cli/commands.py`):
| Exit | Meaning |
|---|---|
@@ -97,7 +97,7 @@ where applicable. CI can gate on these fields without scraping stderr.
### K of N panelists fail
A panel does not fail because one panelist did. Panelists run in parallel
-(`run_panel_parallel`, `src/synth_panel/orchestrator.py`); per-panelist and
+(`run_panel_parallel`, `src/althing/orchestrator.py`); per-panelist and
per-question errors are caught and recorded, not raised:
- Each panelist row in the output carries an `error` field (`null` when
@@ -107,41 +107,41 @@ per-question errors are caught and recorded, not raised:
failure rate.
- The run is declared invalid only when the errored fraction of
panelist-question pairs exceeds `--failure-threshold` (default `0.5`;
- `src/synth_panel/cli/parser.py`). When exceeded, synthesis is
+ `src/althing/cli/parser.py`). When exceeded, synthesis is
auto-disabled (don't synthesize a majority-broken panel) and the run
exits `2`. `--strict` tightens this to zero tolerance (exit `3`).
- `--question-failure-budget N|0.X` contains a *single bad question*
(broken schema, format the model rejects): once that question's failures
cross the threshold it is disabled mid-run, later panelists skip it, and
the envelope reports `disabled_questions` with per-question counts
- (`src/synth_panel/question_budget.py`).
+ (`src/althing/question_budget.py`).
### Synthesis failure and recovery
Synthesis failures never masquerade as a synthesized result: the envelope
carries a top-level `synthesis_error` payload and the run is marked
-invalid (`src/synth_panel/_runners.py`, `src/synth_panel/cli/commands.py`).
+invalid (`src/althing/_runners.py`, `src/althing/cli/commands.py`).
The panelist data is still saved — synthesis is recoverable **post-hoc
without re-running the panel**:
```bash
-synthpanel panel synthesize --synthesis-model sonnet
+althing panel synthesize --synthesis-model sonnet
```
-(`panel synthesize`, `src/synth_panel/cli/parser.py`) re-synthesizes a
+(`panel synthesize`, `src/althing/cli/parser.py`) re-synthesizes a
saved result with a different model or prompt, so a synthesis-model outage
costs you one cheap retry, not the whole panel spend.
Two overflow safeguards on the synthesis step itself:
- Context overflow is detected *before* the call
- (`detect_synthesis_context_overflow`, `src/synth_panel/synthesis.py`);
+ (`detect_synthesis_context_overflow`, `src/althing/synthesis.py`);
`--synthesis-auto-escalate` opts into escalating an overflowing
synthesis to a large-context model (with a visible warning), with
map-reduce sub-chunking as the fallback plan.
- The structured-output engine's 3-strike retry escalates its final strike
**within the run's provider family** (`_escalation_model_for`,
- `src/synth_panel/structured/output.py`): `gemini-*` → `gemini-2.5-pro`,
+ `src/althing/structured/output.py`): `gemini-*` → `gemini-2.5-pro`,
`grok-*` → `grok-4`, OpenAI-compat cheap tiers → the non-cheap sibling,
Anthropic → `sonnet`. A Gemini-only environment never gets asked for an
Anthropic key mid-run; when no stronger same-family model is known, the
@@ -156,8 +156,8 @@ Two overflow safeguards on the synthesis step itself:
gracefully, cancels pending panelists, and emits a valid partial JSON
envelope with `run_invalid: true`, `cost_exceeded: true`,
`halted_at_panelist`, and a `cost_gate` snapshot. Exit code `2`.
- (`CostGate` in `src/synth_panel/cost.py`; wiring in
- `src/synth_panel/cli/commands.py`.)
+ (`CostGate` in `src/althing/cost.py`; wiring in
+ `src/althing/cli/commands.py`.)
- **MCP `max_cost` (GH#576)** — the same gate on the MCP surface: the
`run_panel`, `run_quick_poll`, and `extend_panel` tools accept a
`max_cost` (USD) argument wired into the identical `CostGate` machinery
@@ -172,7 +172,7 @@ Two overflow safeguards on the synthesis step itself:
multi-round refusal). See [docs/mcp.md](mcp.md#max_cost-hard-spend-ceiling).
- **Per-turn telemetry** — token usage is tracked per turn in four buckets
(input / output / cache-write / cache-read; `TokenUsage` and
- `UsageTracker` in `src/synth_panel/cost.py`). Every panelist row and the
+ `UsageTracker` in `src/althing/cost.py`). Every panelist row and the
envelope total carry `usage` and `cost`; multi-model runs are priced
per-model at each provider's actual rate (`aggregate_per_model`), and
models missing from the pricing table produce explicit fallback warnings
@@ -180,12 +180,12 @@ Two overflow safeguards on the synthesis step itself:
- **`--dry-run`** — prints the fully substituted prompts, persona/question
counts, LLM call count, a token estimate, and an **estimated cost** from
the local pricing table, then exits without any provider call
- (`_emit_dry_run_preview`, `src/synth_panel/cli/commands.py`). It also
+ (`_emit_dry_run_preview`, `src/althing/cli/commands.py`). It also
fast-fails config errors a real run would hit (e.g. image attachments
routed to a text-only model).
-- **`synthpanel cost summary`** — post-hoc spend reporting across saved
+- **`althing cost summary`** — post-hoc spend reporting across saved
runs, grouped by model or run, filterable by date
- (`src/synth_panel/cost_summary.py`).
+ (`src/althing/cost_summary.py`).
- MCP mode defaults to `haiku` specifically to keep iterative agent use
cheap; CLI defaults to `sonnet`.
@@ -194,25 +194,25 @@ Two overflow safeguards on the synthesis step itself:
- **Checkpointing + resume** — `--checkpoint-dir` opts into per-run on-disk
snapshots (`//state.json`, atomic writes, per-directory lock
file), flushed every `--checkpoint-every` panelists (default 25;
- `DEFAULT_CHECKPOINT_EVERY` in `src/synth_panel/checkpoint.py`).
+ `DEFAULT_CHECKPOINT_EVERY` in `src/althing/checkpoint.py`).
`--resume ` skips completed panelists, replays the rest, and
merges into one result; `--personas`/`--instrument` may be omitted (they
are recovered from the checkpoint's saved CLI args).
- **Config drift refusal** — resume refuses to continue when the current
config hash does not match the checkpointed one
- (`fingerprint_config`, `src/synth_panel/checkpoint.py`). `--allow-drift`
+ (`fingerprint_config`, `src/althing/checkpoint.py`). `--allow-drift`
downgrades that to a warning and is explicitly documented as
statistically inconsistent. `--force-overwrite` is required to clobber an
existing run id's state.
- **Signal-safe aborts** — when checkpointing is active, SIGINT/SIGTERM
handlers flush a final checkpoint and mark the run aborted
(`install_signal_handlers` / `mark_aborted`,
- `src/synth_panel/checkpoint.py`); the CLI still emits the valid partial
+ `src/althing/checkpoint.py`); the CLI still emits the valid partial
envelope with `abort_reason: "sigint"`. An interrupted 500-persona run
resumes where it stopped instead of restarting from zero.
- **Concurrency and rate limiting** — by default the orchestrator runs one
worker per panelist (`run_panel_parallel`,
- `src/synth_panel/orchestrator.py`). `--max-concurrent N` caps in-flight
+ `src/althing/orchestrator.py`). `--max-concurrent N` caps in-flight
LLM requests at the client layer (all providers on the client);
`--rate-limit-rps` adds a token-bucket requests-per-second cap on top
(fractional values accepted, e.g. `0.5` = one request per two seconds).
@@ -224,7 +224,7 @@ Two overflow safeguards on the synthesis step itself:
panelists (default 50) — stop paying for panelists after the
distribution has stabilized. See [docs/convergence.md](convergence.md).
- **Caps** — panels are bounded at 100 personas / 50 questions
- (`MAX_PERSONAS` / `MAX_QUESTIONS`, `src/synth_panel/_runners.py`),
+ (`MAX_PERSONAS` / `MAX_QUESTIONS`, `src/althing/_runners.py`),
enforced on the MCP and SDK surfaces.
## Determinism and reproducibility
@@ -232,16 +232,16 @@ Two overflow safeguards on the synthesis step itself:
- **`--seed`** is forwarded to providers that support it (OpenAI, Gemini,
xAI, OpenRouter). **Anthropic has no seed parameter** — the client warns
once per provider and proceeds without determinism
- (`src/synth_panel/llm/client.py`,
- `src/synth_panel/llm/providers/anthropic.py`); use `--temperature 0` for
+ (`src/althing/llm/client.py`,
+ `src/althing/llm/providers/anthropic.py`); use `--temperature 0` for
closer-to-deterministic Claude output. Treat seeds as best-effort
bias-reduction, not a bit-exactness guarantee.
- **`--resume`** replays a previously-cached run rather than re-sampling —
the reproducibility tool for "give me the same panel again."
- **Saved-result provenance** — every saved result's metadata embeds the
- resolved models, generation params, synthpanel + Python versions, timing,
+ resolved models, generation params, althing + Python versions, timing,
cost, and a SHA-256 `config_hash` over the resolved config
- (`build_config_hash`, `src/synth_panel/metadata.py`). Template `--var`
+ (`build_config_hash`, `src/althing/metadata.py`). Template `--var`
values are folded in as one-way hashes (`template_vars_fingerprint`) so
runs differing only in substitutions don't collide, without persisting
potentially sensitive raw values.
@@ -251,14 +251,14 @@ See [docs/reproducibility.md](reproducibility.md) for the full statement.
## Credentials
- **Precedence: environment variable first, then the on-disk store**
- (`get_credential`, `src/synth_panel/credentials.py`). Nothing else is
+ (`get_credential`, `src/althing/credentials.py`). Nothing else is
consulted.
-- `synthpanel login` persists a key to
- `~/.config/synthpanel/credentials.json` (override via
- `SYNTHPANEL_CREDENTIALS_PATH` / `XDG_CONFIG_HOME`), written atomically
+- `althing login` persists a key to
+ `~/.config/althing/credentials.json` (override via
+ `ALTHING_CREDENTIALS_PATH` / `XDG_CONFIG_HOME`), written atomically
with file mode `0600`, parent directory `0700`, and a SHA-256 integrity
- sidecar (`save_credential`, `src/synth_panel/credentials.py`).
-- **MCP configs contain no keys by default**: `synthpanel mcp install`
+ sidecar (`save_credential`, `src/althing/credentials.py`).
+- **MCP configs contain no keys by default**: `althing mcp install`
writes an entry with no `env` block unless you explicitly pass
`--env KEY=...`, and writes user-scoped config files with mode `0600`.
Sampling-capable MCP hosts need no key at all (the host's own model does
@@ -267,9 +267,9 @@ See [docs/reproducibility.md](reproducibility.md) for the full statement.
## Observability
- **Structured stderr logs** — `%(asctime)s %(name)s %(levelname)s
- %(message)s` on the `synth_panel` logger namespace
- (`src/synth_panel/logging_config.py`). Level via `--verbose`,
- `SYNTHPANEL_LOG_LEVEL`, or `--debug-all` (which also un-caps chatty HTTP/
+ %(message)s` on the `althing` logger namespace
+ (`src/althing/logging_config.py`). Level via `--verbose`,
+ `ALTHING_LOG_LEVEL`, or `--debug-all` (which also un-caps chatty HTTP/
SDK loggers that are otherwise pinned to WARNING).
- **Clean stream separation** — with `--output-format json`, stdout carries
exactly one JSON document; human-facing progress, hints, and warnings go
@@ -280,7 +280,7 @@ See [docs/reproducibility.md](reproducibility.md) for the full statement.
- **Telemetry in-band** — `failure_stats`, `missing_input_stats`,
`run_invalid`, `abort_reason`, `cost_gate`, `question_failure_budget`,
`convergence`, and `warnings[]` all live in the result envelope
- (`src/synth_panel/cli/commands.py`), and the convergence stream can be
+ (`src/althing/cli/commands.py`), and the convergence stream can be
tee'd as JSON lines via `--convergence-log PATH` for live dashboards.
## What does not exist yet
@@ -298,7 +298,7 @@ Kept here so this page stays trustworthy:
`--question-failure-budget` apply to single-round runs; multi-round
(branching) instruments refuse these flags loudly up front rather than
degrading silently (`_multi_round_flag_errors`,
- `src/synth_panel/cli/commands.py`). The MCP `max_cost` argument mirrors
+ `src/althing/cli/commands.py`). The MCP `max_cost` argument mirrors
the same matrix: instrument inputs (which always dispatch through the
multi-round engine on the MCP surface), ensembles, variants, and
sampling mode refuse it with a typed `INVALID_TOOL_ARG`.
diff --git a/docs/recommended-models.md b/docs/recommended-models.md
index e8697c29..07c92fac 100644
--- a/docs/recommended-models.md
+++ b/docs/recommended-models.md
@@ -1,6 +1,6 @@
# Recommended Models (SynthBench-driven)
-SynthPanel can consult the [SynthBench](https://synthbench.org) public
+Althing can consult the [SynthBench](https://synthbench.org) public
leaderboard to pick the best-ranked model for the kind of research you're
running. This closes the credibility loop: scores measured on the bench
drive defaults in the harness.
@@ -9,20 +9,20 @@ drive defaults in the harness.
```bash
# Use the top-ranked model for a specific topic
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument pricing-discovery \
--var problem="choosing a project management tool" \
--best-model-for "Economy & Work"
# Top-ranked model across a whole dataset (by SPS)
-synthpanel panel run ... --best-model-for ":globalopinionqa"
+althing panel run ... --best-model-for ":globalopinionqa"
# Topic within a non-default dataset
-synthpanel panel run ... --best-model-for "Technology & Digital Life:globalopinionqa"
+althing panel run ... --best-model-for "Technology & Digital Life:globalopinionqa"
```
-Before the run, SynthPanel prints a recommendation line to stderr so you
+Before the run, Althing prints a recommendation line to stderr so you
can cancel and override:
```
@@ -48,33 +48,33 @@ recommendation will drift from leaderboard reality after the snapshot.
## How it works
-1. On first use, SynthPanel fetches
+1. On first use, Althing fetches
`https://synthbench.org/data/leaderboard.json` and caches it at
- `~/.synthpanel/synthbench-cache.json` for 24 hours.
+ `~/.althing/synthbench-cache.json` for 24 hours.
2. Entries are filtered to the requested `dataset` (default
`globalopinionqa`), then ranked — by the named topic's score when a
topic is given, otherwise by overall SPS.
-3. The top entry's `model` field is resolved through SynthPanel's alias
+3. The top entry's `model` field is resolved through Althing's alias
table (so `"haiku"` becomes `claude-haiku-4-5-20251001`) and stamped
onto `--model` for the rest of the pipeline.
> **Note (GH #494, v1.5.1+):** The canonical leaderboard URL is currently
-> 404'ing upstream. SynthPanel ships a **bundled snapshot** (taken
-> 2026-04-24) at `synth_panel/data/synthbench-snapshot.json` and falls
+> 404'ing upstream. Althing ships a **bundled snapshot** (taken
+> 2026-04-24) at `althing/data/synthbench-snapshot.json` and falls
> back to it when the live URL is unreachable AND no user cache exists.
> The fallback produces a real recommendation on stderr and tags the
> entry as `source=bundled-snapshot`. To override with your own mirror,
-> set `SYNTHPANEL_SYNTHBENCH_URL=...`.
+> set `ALTHING_SYNTHBENCH_URL=...`.
### Environment knobs
-- `SYNTHPANEL_SYNTHBENCH_URL` — override the fetch URL (useful for
+- `ALTHING_SYNTHBENCH_URL` — override the fetch URL (useful for
internal mirrors, forks, or air-gapped environments — and the
documented workaround for the GH #494 outage).
-- `SYNTHPANEL_SYNTHBENCH_OFFLINE=1` — never hit the network; use the
+- `ALTHING_SYNTHBENCH_OFFLINE=1` — never hit the network; use the
cache if present, otherwise the bundled snapshot, otherwise skip the
recommendation.
-- `SYNTHPANEL_SYNTHBENCH_REFRESH=1` — bypass the 24h TTL and force a
+- `ALTHING_SYNTHBENCH_REFRESH=1` — bypass the 24h TTL and force a
fresh fetch (ignores the cached ETag).
- `SYNTH_PANEL_DATA_DIR` — override the data dir where the cache lives.
@@ -89,13 +89,13 @@ on stderr so agents and humans can both see how degraded the answer is.
- **Stale cache + 304** → conditional GET confirms cache is current.
Recommendation tagged `source=live` and the cache timestamp is
refreshed. No stderr noise.
-- **Stale cache + network error** → stderr `synthpanel: synthbench
+- **Stale cache + network error** → stderr `althing: synthbench
fetch failed (…); using stale cache from (source=stale-cache)`.
Recommendation tagged `source=stale-cache`.
- **No cache + network error** → bundled snapshot fallback (sy-nkh):
- stderr `synthpanel: synthbench unavailable (…); using bundled
+ stderr `althing: synthbench unavailable (…); using bundled
snapshot from YYYY-MM-DD (source=bundled-snapshot) — override the URL
- via $SYNTHPANEL_SYNTHBENCH_URL if you have a mirror …`. Recommendation
+ via $ALTHING_SYNTHBENCH_URL if you have a mirror …`. Recommendation
tagged `source=bundled-snapshot` and the CLI also emits a follow-up
note explaining the implication and the override path.
- **Offline mode + fresh cache** → recommendation tagged
@@ -117,13 +117,13 @@ explicit instead of pretending the data is current.
### Reading the source field from code
-The wire field is part of the public `synth_panel.synthbench`
+The wire field is part of the public `althing.synthbench`
surface — `Recommendation.source` and `LoadedLeaderboard.source` both
expose the same closed enum. Allowed values are exported as
-`synth_panel.synthbench.RECOMMENDATION_SOURCES`:
+`althing.synthbench.RECOMMENDATION_SOURCES`:
```python
-from synth_panel import synthbench
+from althing import synthbench
rec = synthbench.recommend("Economy & Work")
if rec is None:
@@ -163,8 +163,8 @@ CLI flag or [synthbench.org](https://synthbench.org) for current picks.
## Caveats
- **Display labels & runnable ids (gh-519).** Some leaderboard rows carry a
- human-readable display label (e.g. `SynthPanel (Gemini Flash Lite)`) in
- their `model` field rather than a runnable provider model id. SynthPanel
+ human-readable display label (e.g. `Althing (Gemini Flash Lite)`) in
+ their `model` field rather than a runnable provider model id. Althing
never stamps such a label onto `--model`. Instead it substitutes a runnable
id in this order:
1. The row's runnable `model_id` (e.g. `google/gemini-2.5-flash-lite`)
@@ -174,14 +174,14 @@ CLI flag or [synthbench.org](https://synthbench.org) for current picks.
without a `model_id`, a base model inferred from the entry's `config_id`,
adopted only when it resolves to a recognized provider id or alias.
3. If neither yields a runnable id, the recommendation is **refused** with
- an actionable stderr message and SynthPanel keeps your existing
+ an actionable stderr message and Althing keeps your existing
`--model`/default. A stderr note records any substitution.
- **Sparse topics.** When the top entry's `run_count < 3`, a
low-confidence warning is emitted. Treat those recommendations as
suggestive rather than authoritative.
- **Provider/model strings vary.** The leaderboard publishes the raw
`model` string the run used — sometimes a canonical id, sometimes a
- short alias. SynthPanel passes the string through the alias resolver
+ short alias. Althing passes the string through the alias resolver
so either shape works, but the raw value is preserved in the
recommendation line as `raw_model`.
diff --git a/docs/registry-submissions.md b/docs/registry-submissions.md
index dd77a363..b4acc066 100644
--- a/docs/registry-submissions.md
+++ b/docs/registry-submissions.md
@@ -4,7 +4,7 @@
**Status:** Prep artifacts committed; human-only submit steps below
**Last updated:** 2026-04-19
-This is a checklist for submitting SynthPanel to major MCP registries. The
+This is a checklist for submitting Althing to major MCP registries. The
code-doable prep work is already done (`glama.json`, `server.json`); the
remaining steps require interactive auth or web forms and must be completed
by a maintainer.
@@ -23,12 +23,12 @@ by a maintainer.
**Long description (for forms with room):**
-> SynthPanel is a lightweight, LLM-agnostic research harness for running
+> Althing is a lightweight, LLM-agnostic research harness for running
> synthetic focus groups using AI personas. Define personas in YAML, define
> your research instrument in YAML, and run against any LLM — from your
> terminal, from a pipeline, or from an AI agent's MCP tool call. Includes
> a 12-tool MCP server for Claude Code / Cursor / Windsurf. MIT licensed.
-> Benchmark score: SPS 0.90 on SynthBench. pip install synthpanel[mcp].
+> Benchmark score: SPS 0.90 on SynthBench. pip install althing[mcp].
**Category / tags (where supported):**
@@ -38,10 +38,10 @@ by a maintainer.
**Links:**
-- Site:
-- Repo:
-- PyPI:
-- MCP docs:
+- Site:
+- Repo:
+- PyPI:
+- MCP docs:
- Benchmark:
---
@@ -50,7 +50,7 @@ by a maintainer.
**Status:** Prep committed · Claim flow required
-Glama auto-indexes GitHub repos with the `mcp` topic; SynthPanel's repo
+Glama auto-indexes GitHub repos with the `mcp` topic; Althing's repo
already has the topic set, so the listing should appear on its own. To
claim ownership (required to edit the listing, configure a Docker image,
see usage reports), we've committed `glama.json` to the repo root with
@@ -60,14 +60,14 @@ both org admins listed as maintainers.
1. Sign in at with GitHub (as `the-data-viking` or
`openclaw-dv`). Either admin works since both are in `glama.json`.
-2. Search for `synthpanel` in the registry. If the server appears:
+2. Search for `althing` in the registry. If the server appears:
visit its page → **Claim server** → follow the GitHub OAuth flow.
3. If the server does **not** appear yet, use the **Add Server** button
at and paste
- `https://github.com/DataViking-Tech/SynthPanel`. Glama will index
+ `https://github.com/DataViking-Tech/Althing`. Glama will index
within minutes and the claim flow becomes available.
4. Once claimed, update the server metadata:
- - **Title:** SynthPanel
+ - **Title:** Althing
- **Tagline:** (use the one-liner above)
- **Description:** (use the standard description above)
5. Record the live URL below.
@@ -89,7 +89,7 @@ either through the `smithery` CLI (authenticated via Smithery API key) or
through Smithery's web UI.
A `smithery.yaml` manifest is useful only for Smithery's hosted/bundled
-deployment modes (JS module upload, MCPB bundle, container build). SynthPanel
+deployment modes (JS module upload, MCPB bundle, container build). Althing
ships as a PyPI package invoked via `uvx`, so the appropriate submission path
is **URL-based** — point Smithery at the GitHub repo; it will scan and index
the server metadata (tools, README, install instructions).
@@ -105,14 +105,14 @@ the server metadata (tools, README, install instructions).
3. Install and run the Smithery CLI to publish the repo URL:
```bash
npx @smithery/cli mcp publish \
- https://github.com/DataViking-Tech/SynthPanel \
- -n synthpanel
+ https://github.com/DataViking-Tech/Althing \
+ -n althing
```
- The CLI registers SynthPanel under the qualified name `synthpanel` and
+ The CLI registers Althing under the qualified name `althing` and
scans the linked repo for metadata. If the CLI path fails, fall back
to the web submission form at .
4. Edit the listing via the Smithery dashboard to set:
- - **Title:** SynthPanel
+ - **Title:** Althing
- **Tagline:** (use the one-liner above)
- **Description:** (use the standard description above)
- **Tags:** research, survey, personas, llm, mcp, python
@@ -122,7 +122,7 @@ the server metadata (tools, README, install instructions).
**If Smithery requires a deployable bundle (MCPB / container) rather than a
URL-only listing:** this escalates from a ~10 min submission into a packaging
-project. File a separate bead (`Package SynthPanel as MCPB bundle for
+project. File a separate bead (`Package Althing as MCPB bundle for
Smithery hosted deploy`) before attempting — do not improvise the packaging
inside this submission sweep.
@@ -139,8 +139,8 @@ auto-ingests from it daily, so a single publish here yields both
listings. The `server.json` manifest is already committed at the repo
root and describes:
-- PyPI package `synthpanel`, version 0.9.1
-- `runtimeHint: uvx` → clients run `uvx synthpanel[mcp] synthpanel mcp-serve`
+- PyPI package `althing`, version 0.9.1
+- `runtimeHint: uvx` → clients run `uvx althing[mcp] althing mcp-serve`
- stdio transport
- All four optional API-key env vars
@@ -162,7 +162,7 @@ root and describes:
mcp-publisher publish
```
The CLI reads `./server.json` automatically.
-4. Verify at .
+4. Verify at .
5. Record the listing URL below.
**Recorded URL:** `__ TBD — fill after publish __`
@@ -186,10 +186,10 @@ should appear within 7 days with no additional action.
**Human steps (only if the auto-ingest doesn't pick it up):**
1. Wait 7–10 days after the Official MCP Registry publish.
-2. Search for `synthpanel`.
+2. Search for `althing`.
3. If missing, submit manually at :
- **Type:** Server
- - **URL:** `https://github.com/DataViking-Tech/SynthPanel`
+ - **URL:** `https://github.com/DataViking-Tech/Althing`
4. For metadata adjustments, email `[email protected]`.
5. Record the URL below.
@@ -248,7 +248,7 @@ remains out of scope.)
**Recommendation:** skip for this submission sweep. If Klavis listing
becomes strategically important, file a separate bead scoped as
-"Evaluate + implement Klavis integration for SynthPanel" (estimated:
+"Evaluate + implement Klavis integration for Althing" (estimated:
days, not hours).
---
@@ -264,7 +264,7 @@ submissions go live, to allow indexing + propagation. Test queries:
- `"python mcp server for user research"`
Run these on ChatGPT, Claude, Perplexity, and Gemini. Score
-SynthPanel's surface: cited / mentioned / missing. File as a separate
+Althing's surface: cited / mentioned / missing. File as a separate
bead (the test itself is deliverable-producing work).
---
diff --git a/docs/registry.md b/docs/registry.md
index d97884f1..737836e2 100644
--- a/docs/registry.md
+++ b/docs/registry.md
@@ -2,11 +2,11 @@
## Builtin vs Registry packs
-synthpanel has two pack sources, and the difference matters when you're trying
+althing has two pack sources, and the difference matters when you're trying
to find one:
-- **Builtin packs** ship inside the `synthpanel` wheel. They are resolvable by
- name the moment `pip install synthpanel` finishes — no `pack import`, no
+- **Builtin packs** ship inside the `althing` wheel. They are resolvable by
+ name the moment `pip install althing` finishes — no `pack import`, no
network, no registry lookup. The SDK currently bundles **14 persona packs**
(232 personas total: `ai-eval-buyers`, `broad-professionals`, `developer`,
`enterprise-ai-buyers`, `enterprise-buyer`, `general-consumer`,
@@ -20,7 +20,7 @@ to find one:
for the same list with per-pack persona counts.
- **Registry packs** are community-authored. They live in third-party GitHub
repos and are listed in the registry index described below. You pull them
- with `synthpanel pack import gh:user/repo`.
+ with `althing pack import gh:user/repo`.
If you searched the registry for a builtin pack name and came up empty, that's
expected — the registry only indexes community-authored packs. Use the builtin
@@ -29,8 +29,8 @@ name directly with `--personas` or `--instrument`.
## The registry
The registry itself is a JSON index (`default.json`) hosted at
-[`DataViking-Tech/synthpanel-registry`](https://github.com/DataViking-Tech/synthpanel-registry).
-Anyone can add their pack to it via a pull request. synthpanel caches the index
+[`DataViking-Tech/althing-registry`](https://github.com/DataViking-Tech/althing-registry).
+Anyone can add their pack to it via a pull request. althing caches the index
locally for 24 hours and falls back to a stale copy when the network is
unreachable, so `pack import` keeps working offline.
@@ -42,18 +42,18 @@ unreachable, so `pack import` keeps working offline.
|---|---|
| Registry id | `icp-demo` |
| `gh:user/repo[@ref][:path]` | `gh:dataviking-tech/example-pack` |
-| `https://github.com/.../blob/...` | `https://github.com/dv/pk/blob/main/synthpanel-pack.yaml` |
-| `https://raw.githubusercontent.com/...` | `https://raw.githubusercontent.com/dv/pk/main/synthpanel-pack.yaml` |
+| `https://github.com/.../blob/...` | `https://github.com/dv/pk/blob/main/althing-pack.yaml` |
+| `https://raw.githubusercontent.com/...` | `https://raw.githubusercontent.com/dv/pk/main/althing-pack.yaml` |
### Registry ids
```bash
# Resolve a bare registry id to its source and install it
-synthpanel pack import icp-demo
+althing pack import icp-demo
```
When the source is a bare id (a slug — no path separator or `.yaml`/`.yml`/
-`.json` extension) that is **not** a local file, synthpanel looks it up in the
+`.json` extension) that is **not** a local file, althing looks it up in the
registry and imports from the resolved `gh:` source. The pack installs under
the registry id, so the command `panel run --personas ` suggests after a
miss (`pack import `, then `--personas `) works end to end. Ids that
@@ -63,21 +63,21 @@ aren't in the registry fall through to local-file handling and produce a
### `gh:` URIs
```bash
-# Default ref (main), default path (synthpanel-pack.yaml)
-synthpanel pack import gh:dataviking-tech/example-pack
+# Default ref (main), default path (althing-pack.yaml)
+althing pack import gh:dataviking-tech/example-pack
# Pin to a tag or commit SHA
-synthpanel pack import gh:dataviking-tech/example-pack@v0.2.0
-synthpanel pack import gh:dataviking-tech/example-pack@3a7f1c0
+althing pack import gh:dataviking-tech/example-pack@v0.2.0
+althing pack import gh:dataviking-tech/example-pack@3a7f1c0
# Non-default YAML path inside the repo
-synthpanel pack import gh:dataviking-tech/example-pack:packs/contrarian.yaml
+althing pack import gh:dataviking-tech/example-pack:packs/contrarian.yaml
# Ref + path together
-synthpanel pack import gh:dataviking-tech/example-pack@v0.2.0:packs/contrarian.yaml
+althing pack import gh:dataviking-tech/example-pack@v0.2.0:packs/contrarian.yaml
```
-When no `:path` is given, the resolver tries `synthpanel-pack.yaml` at the repo
+When no `:path` is given, the resolver tries `althing-pack.yaml` at the repo
root first. If that file is missing, it inspects the root via the GitHub
Contents API and — if and only if there is exactly one `*.yaml`/`*.yml` file
there — imports that one. Two or more root-level YAML files is a `ValueError`
@@ -85,13 +85,13 @@ asking you to pick one explicitly.
### Publishable filename
-The publishable default is **`synthpanel-pack.yaml`** (namespaced so it will not
+The publishable default is **`althing-pack.yaml`** (namespaced so it will not
collide with unrelated `pack.yaml` files in the same repo). Authors who drop a
single file at the repo root should use exactly that name.
### HTTPS forms
-Paste any GitHub `blob/` URL directly; synthpanel rewrites it to the
+Paste any GitHub `blob/` URL directly; althing rewrites it to the
corresponding `raw.githubusercontent.com` URL and fetches it. Pre-rewritten
`raw.githubusercontent.com/...` URLs are accepted as-is. No magic for other
hosts — if the URL starts with `https://` but is not a GitHub address, the
@@ -101,7 +101,7 @@ import fails with a clear error.
By default, `pack import` will **only import packs that are listed in the
registry**. This is a soft trust check: inclusion requires a PR to
-`synthpanel-registry`, which gets basic sanity review before merge.
+`althing-registry`, which gets basic sanity review before merge.
A pack is considered registered when the registry contains an entry whose
`repo` matches `user/repo` from your `gh:` source and whose `ref` matches the
@@ -113,11 +113,11 @@ stable `user/repo@ref` to match on).
To import a pack that is not in the registry, pass `--unverified`:
```bash
-synthpanel pack import gh:some-user/not-yet-submitted-pack --unverified
+althing pack import gh:some-user/not-yet-submitted-pack --unverified
```
The import prints a one-time warning block with the source URL, the SHA-256
-checksum of the YAML body as it was fetched, and the id synthpanel saved it
+checksum of the YAML body as it was fetched, and the id althing saved it
under. Keep that checksum if you care about pinning — there is no TOFU cache
yet; `--unverified` only gates the registry check.
@@ -127,7 +127,7 @@ unnecessary.` message on stderr — the import proceeds normally.
## Pack IDs and Collisions
-synthpanel needs a unique `pack_id` to save the pack under. It resolves the id
+althing needs a unique `pack_id` to save the pack under. It resolves the id
in this priority order:
1. `--id ` if you passed it explicitly
@@ -139,13 +139,13 @@ Two collision cases are enforced before anything touches disk:
| Collision | Result |
|---|---|
-| id matches a **bundled pack** (ships inside the synthpanel wheel) | Hard error — bundled ids are reserved. Re-run with `--id ` to import under a different name. |
+| id matches a **bundled pack** (ships inside the althing wheel) | Hard error — bundled ids are reserved. Re-run with `--id ` to import under a different name. |
| id matches an **existing user-saved pack** | Hard error. Re-run with `--force` to overwrite, or `--id ` to keep both. |
Example — collision with an existing user pack:
```
-$ synthpanel pack import gh:alice/panel-pack
+$ althing pack import gh:alice/panel-pack
Error: pack id 'panel-pack' already exists as a user-saved pack.
Re-run with --force to overwrite, or --id for a new copy.
```
@@ -157,20 +157,20 @@ defaults to the YAML `name:` field, falling back to the pack id.
The registry cache lives at
`$SYNTH_PANEL_DATA_DIR/registry-cache.json` (default
-`~/.synthpanel/registry-cache.json`). Fresh fetches use `If-None-Match` against
+`~/.althing/registry-cache.json`). Fresh fetches use `If-None-Match` against
the cached `ETag`, so repeated calls are cheap.
| Env var | Effect |
|---|---|
-| `SYNTHPANEL_REGISTRY_URL` | Override the registry URL (useful for forks, air-gapped setups, tests). |
-| `SYNTHPANEL_REGISTRY_REFRESH=1` | Force a network fetch even if the cached copy is fresh. |
-| `SYNTHPANEL_REGISTRY_OFFLINE=1` | Skip the network; use the cached copy, or an empty registry if none exists. |
+| `ALTHING_REGISTRY_URL` | Override the registry URL (useful for forks, air-gapped setups, tests). |
+| `ALTHING_REGISTRY_REFRESH=1` | Force a network fetch even if the cached copy is fresh. |
+| `ALTHING_REGISTRY_OFFLINE=1` | Skip the network; use the cached copy, or an empty registry if none exists. |
| `SYNTH_PANEL_DATA_DIR` | Override the on-disk cache location. |
-When the cache is older than 24 hours and the fetch fails, synthpanel keeps
+When the cache is older than 24 hours and the fetch fails, althing keeps
using the stale copy — operations never block on the network. When there is
no cache at all and the fetch fails, you get an empty registry; registered-only
-imports will then fail with the standard `not in the synthpanel registry`
+imports will then fail with the standard `not in the althing registry`
error, and you can fall back to `--unverified` if you know what you are
importing.
@@ -179,7 +179,7 @@ importing.
Any valid persona pack YAML can be published. Minimum shape:
```yaml
-# synthpanel-pack.yaml (at the repo root — the default path)
+# althing-pack.yaml (at the repo root — the default path)
name: Contrarian Stress Pack
version: "1" # optional; defaults to "1" when omitted
description: >
@@ -210,27 +210,27 @@ complete working example.
### Filename convention
-Put the pack at `synthpanel-pack.yaml` in the repo root if the repo is a
+Put the pack at `althing-pack.yaml` in the repo root if the repo is a
dedicated pack repo. If the repo contains multiple packs, put them under a
subdirectory and document the `gh:user/repo:packs/.yaml` form in your
-README — synthpanel will not guess across directories.
+README — althing will not guess across directories.
## Contributing a Pack to the Registry
The registry is a separate repository:
-[`DataViking-Tech/synthpanel-registry`](https://github.com/DataViking-Tech/synthpanel-registry).
+[`DataViking-Tech/althing-registry`](https://github.com/DataViking-Tech/althing-registry).
The contribution flow:
1. Publish your pack in its own GitHub repo (public). Tag a release if you
want users to be able to pin to `@v…`.
-2. Open a PR against `synthpanel-registry` adding a new entry to
+2. Open a PR against `althing-registry` adding a new entry to
`default.json`. See that repo's
- [`CONTRIBUTING.md`](https://github.com/DataViking-Tech/synthpanel-registry/blob/main/CONTRIBUTING.md)
+ [`CONTRIBUTING.md`](https://github.com/DataViking-Tech/althing-registry/blob/main/CONTRIBUTING.md)
for the entry schema and review bar.
-3. Once merged, `synthpanel pack import gh:/` works without
+3. Once merged, `althing pack import gh:/` works without
`--unverified` for anyone whose cache refreshes — within 24h for most
- users, immediately with `SYNTHPANEL_REGISTRY_REFRESH=1`.
+ users, immediately with `ALTHING_REGISTRY_REFRESH=1`.
The registry review is intentionally light. It checks the entry is
well-formed, the repo is reachable, the YAML parses as a persona pack, and
@@ -245,15 +245,15 @@ The repo, ref, or path does not exist — or the repo is private. `GITHUB_TOKEN`
auth for private repos is planned; for now, download the YAML and use the
local-file form of `pack import`.
-**`Error: pack '' is not in the synthpanel registry.`**
+**`Error: pack '' is not in the althing registry.`**
Either submit an entry to the registry (see above), or re-run with
`--unverified` if you are importing something you trust.
**`multiple yaml files at root of user/repo@ref: [...]`**
The fallback resolver only accepts a single root-level YAML. Either rename
-your pack file to `synthpanel-pack.yaml`, or import with an explicit path:
+your pack file to `althing-pack.yaml`, or import with an explicit path:
`gh:user/repo:path/to/pack.yaml`.
**Stale data after you submitted a registry PR.**
Your local cache is up to 24h old. Force a refresh:
-`SYNTHPANEL_REGISTRY_REFRESH=1 synthpanel pack import gh:you/your-pack`.
+`ALTHING_REGISTRY_REFRESH=1 althing pack import gh:you/your-pack`.
diff --git a/docs/release-audit-2026-04-15.md b/docs/release-audit-2026-04-15.md
index ef2bc8a6..d3be38fe 100644
--- a/docs/release-audit-2026-04-15.md
+++ b/docs/release-audit-2026-04-15.md
@@ -1,6 +1,6 @@
# Pre-public-release audit — 2026-04-15
-Audit for the synthpanel (PyPI: `synthpanel`; GitHub: currently `DataViking-Tech/synth-panel`) pre-public-flip. Bead: `sp-9m9`.
+Audit for the althing (PyPI: `althing`; GitHub: currently `DataViking-Tech/synth-panel`) pre-public-flip. Bead: `sp-9m9`.
## Verdict: **READY-TO-FLIP** (after the in-place fixes landed in this PR)
@@ -39,29 +39,29 @@ Tracked files with any Gas-Town / polecat flavor before this PR:
| `CLAUDE.md` | **Keep** — it's a generic project guide for AI coding assistants (Claude Code, Cursor, etc.), no internal/agent references. Publicly useful. |
| `.claude-plugin/plugin.json` | **Keep** — Claude Code plugin manifest, intentionally shipped. |
| `gastown-rig-settings.example.json` | **REMOVED** in this PR — references internal "Gas Town rig" system the public has no context for. |
-| `CODEOWNERS` (root) | **REMOVED** in this PR — conflicted with `.github/CODEOWNERS` (root said `@DataViking-Tech/core`, `.github/` says `@DataViking-Tech/synthpanel`; `.github/` takes precedence and is the one that actually matches the org). |
-| `src/synth_panel/cli/commands.py:915` | **Keep** — single code-comment reference to "refinery" as a generic automation example. Not blocking; could be generalized in a future pass. |
+| `CODEOWNERS` (root) | **REMOVED** in this PR — conflicted with `.github/CODEOWNERS` (root said `@DataViking-Tech/core`, `.github/` says `@DataViking-Tech/althing`; `.github/` takes precedence and is the one that actually matches the org). |
+| `src/althing/cli/commands.py:915` | **Keep** — single code-comment reference to "refinery" as a generic automation example. Not blocking; could be generalized in a future pass. |
Untracked (already in `.gitignore` before this PR): `.claude/`, `.beads/`, `.runtime/`, `CLAUDE.local.md` (the last one added to `.gitignore` in this PR defensively — it's a polecat-only file that happens to be untracked currently).
### 4. Documentation review — **PASS** (after fix)
-- **README.md** (463 lines): strong public-facing intro. Clear "what / why / quick-start" in the first 70 lines; runnable `pip install synthpanel` command in the first code fence. Covers v3 branching, providers, MCP, ensemble blending, methodology caveats. Only fix: one `git+https://…/synthpanel.git` URL updated to `synth-panel.git` (line 34).
+- **README.md** (463 lines): strong public-facing intro. Clear "what / why / quick-start" in the first 70 lines; runnable `pip install althing` command in the first code fence. Covers v3 branching, providers, MCP, ensemble blending, methodology caveats. Only fix: one `git+https://…/althing.git` URL updated to `synth-panel.git` (line 34).
- **SPEC.md** (794 lines): functional spec — appropriate for public, gives external contributors a clean-room reference.
- **CHANGELOG.md** (was 81 lines, now 131): had a real hole — entries jumped from 0.4.1 straight to 0.8.0 with no 0.5 / 0.6 / 0.7 entries, despite `v0.5.0`, `v0.6.0`, `v0.7.0..v0.7.4`, `v0.8.0` tags all existing. Backfilled minimal entries for 0.5.0, 0.6.0, 0.7.0, and a 0.7.4 patch-series note; added the missing footer link refs. Content cross-references the README Versions table rather than re-narrating release notes.
- **LICENSE**: MIT, © 2026 DataViking Tech. Valid.
- **SECURITY.md**: present, reports to `security@dataviking.tech`, 48h ack / 7d fix target. Good.
- **CODE_OF_CONDUCT.md**: Contributor Covenant 2.1 adoption with enforcement contact. Good.
- **CONTRIBUTING.md**: dev setup, tests, lint, release process, DCO sign-off policy. Updated the `git clone` URL to `synth-panel`.
-- **.github/ISSUE_TEMPLATE/**: `bug_report.yml`, `feature_request.yml`, `adapter_proposal.yml`, `config.yml` present. URLs in `config.yml` pointed at the wrong repo name (`synthpanel` vs actual `synth-panel`) — fixed in this PR.
+- **.github/ISSUE_TEMPLATE/**: `bug_report.yml`, `feature_request.yml`, `adapter_proposal.yml`, `config.yml` present. URLs in `config.yml` pointed at the wrong repo name (`althing` vs actual `synth-panel`) — fixed in this PR.
- **.github/pull_request_template.md**: present, semver-label-aware, DCO-aware, adapter section. Good.
-- **docs/stability.md**: describes pre-1.0 breakage policy + enumerates public surface. Updated in this PR to add `synth_panel.cost.lookup_pricing_by_provider` (added in 0.8.0) and to reconcile "synth-panel" → "synthpanel" naming for consistency with the package name.
+- **docs/stability.md**: describes pre-1.0 breakage policy + enumerates public surface. Updated in this PR to add `althing.cost.lookup_pricing_by_provider` (added in 0.8.0) and to reconcile "synth-panel" → "althing" naming for consistency with the package name.
- **docs/mcp.md**, **docs/adapter-guide.md**, **docs/RELEASING.md**: present, accurate, publicly appropriate.
### 5. Governance & supply chain — **PASS** (after fix)
-- **`.github/CODEOWNERS`**: `* @DataViking-Tech/synthpanel`. Valid.
-- **pyproject.toml `[project]`**: `name`, `description`, `license` (MIT), `authors`, `readme`, `requires-python` (>=3.10), `classifiers`, `keywords` — all present and appropriate. Optional deps (`mcp`, `dev`) declared. Entry point `synthpanel = synth_panel.main:main`. URLs updated in this PR from `synthpanel` → `synth-panel`.
+- **`.github/CODEOWNERS`**: `* @DataViking-Tech/althing`. Valid.
+- **pyproject.toml `[project]`**: `name`, `description`, `license` (MIT), `authors`, `readme`, `requires-python` (>=3.10), `classifiers`, `keywords` — all present and appropriate. Optional deps (`mcp`, `dev`) declared. Entry point `althing = althing.main:main`. URLs updated in this PR from `althing` → `synth-panel`.
- **CI** (`.github/workflows/ci.yml`): `lint` (ruff check + format), `typecheck` (mypy), `security` (pip-audit), `test` (pytest matrix on Python 3.10–3.14, experimental=true on 3.14, 80% coverage floor). Actions pinned by SHA. Good.
- **Publish** (`.github/workflows/publish.yml` + `publish-test.yml` + `auto-tag.yml`): trusted publishing to PyPI via semver labels on merged PRs.
- **Dependency management**: `renovate.json` present — auto-merge patch, group minor, group GitHub Actions, weekly cadence, `prConcurrentLimit: 5`. Renovate is the counterpart to Dependabot; both would be redundant. No Dependabot config needed.
@@ -77,9 +77,9 @@ Untracked (already in `.gitignore` before this PR): `.claude/`, `.beads/`, `.run
### 7. API stability claims — **PASS** (after fix)
-- `docs/stability.md` correctly frames synthpanel as pre-1.0 with minor-bumps-may-break, patch-bumps-never-break.
+- `docs/stability.md` correctly frames althing as pre-1.0 with minor-bumps-may-break, patch-bumps-never-break.
- Public surface enumerated: `LLMProvider` base, adapter contract types, CLI commands, MCP tool signatures, YAML instrument / persona formats.
-- **Added in this PR:** `synth_panel.cost.lookup_pricing_by_provider(provider_string)` — the public helper added in 0.8.0 (`sp-027`) — was missing from the public-surface list. Now enumerated.
+- **Added in this PR:** `althing.cost.lookup_pricing_by_provider(provider_string)` — the public helper added in 0.8.0 (`sp-027`) — was missing from the public-surface list. Now enumerated.
- The 0.8.0 CHANGELOG entry already documents the addition correctly.
### 8. Examples & developer experience — **PASS**
@@ -89,16 +89,16 @@ Untracked (already in `.gitignore` before this PR): `.claude/`, `.beads/`, `.run
- **Fresh-venv smoke test** (executed during audit):
- `python3.14 -m venv /tmp/…`
- `pip install .` → build succeeded, wheel installed, 922/922 unit tests would pass.
- - `synthpanel --help` → correct help output with all subcommands.
- - `synthpanel instruments list` → all 8 bundled packs listed with descriptions.
- - `synthpanel --version` → `synthpanel 0.8.0`.
-- Quickstart in README works for a fresh user with just `pip install synthpanel` + an API key.
+ - `althing --help` → correct help output with all subcommands.
+ - `althing instruments list` → all 8 bundled packs listed with descriptions.
+ - `althing --version` → `althing 0.8.0`.
+- Quickstart in README works for a fresh user with just `pip install althing` + an API key.
### 9. Repo metadata (pre-rename snapshot)
- Current remote: `https://github.com/DataViking-Tech/synth-panel.git` (hyphenated).
- pyproject + all doc URLs now point to `synth-panel` (hyphenated, current).
-- After operator executes the `synth-panel` → `synthpanel` rename, a one-line find/replace PR can swap these; GitHub auto-redirects old URLs in the interim so nothing breaks.
+- After operator executes the `synth-panel` → `althing` rename, a one-line find/replace PR can swap these; GitHub auto-redirects old URLs in the interim so nothing breaks.
- GitHub description / topics / homepage URL not verified from this worktree (network unavailable to `api.github.com` at audit time); flagged in the operator checklist.
### 10. Quality gates — **PASS**
@@ -107,7 +107,7 @@ Ran against the head of this PR:
- `ruff check src/ tests/` → all checks passed
- `ruff format --check src/ tests/` → 87 files already formatted
-- `mypy src/synth_panel/` → no issues found in 54 source files
+- `mypy src/althing/` → no issues found in 54 source files
- `pytest tests/ --ignore=tests/test_acceptance.py` → **922 passed**, total coverage **86.87%** (floor is 80%)
## Required actions before flip
@@ -117,16 +117,16 @@ Ran against the head of this PR:
## Recommended actions (non-blocking)
1. **Verify branch protection on `main`** before flip: require PR + 1 approval + all 4 CI checks (lint, typecheck, security, test) green. The merge queue is already pr-mode per the Gas Town rig config, but when the repo is public the UI-level protections should be explicit.
-2. **Generalize the `refinery` comment** in `src/synth_panel/cli/commands.py:915` (*"automation (CI, refinery, wrapper scripts) can detect silent-failure scenarios"*) on a future non-urgent pass. Not publicly confusing, just slightly internal-flavored. Filed as a future-cleanup candidate; not worth blocking the flip.
+2. **Generalize the `refinery` comment** in `src/althing/cli/commands.py:915` (*"automation (CI, refinery, wrapper scripts) can detect silent-failure scenarios"*) on a future non-urgent pass. Not publicly confusing, just slightly internal-flavored. Filed as a future-cleanup candidate; not worth blocking the flip.
## Post-flip checklist (operator)
-1. GitHub Settings → rename `synth-panel` → `synthpanel` (cosmetic; PyPI name already correct).
+1. GitHub Settings → rename `synth-panel` → `althing` (cosmetic; PyPI name already correct).
2. Settings → Visibility → Public.
3. PR with version bump `0.8.0` → `0.9.0` + CHANGELOG entry, `semver:minor` label.
4. Verify `Auto Semver Tag` → `Publish to PyPI` fires cleanly on merge.
-5. Update synthbench `pyproject.toml` to pin `synthpanel>=0.9.0`.
+5. Update synthbench `pyproject.toml` to pin `althing>=0.9.0`.
6. Add public-launch announcement (blog / Twitter / HN Show HN).
-7. Drop-in find/replace of `DataViking-Tech/synth-panel` → `DataViking-Tech/synthpanel` across README/CHANGELOG/pyproject/CONTRIBUTING/ISSUE_TEMPLATE/config.yml once the rename is executed (GitHub redirects mean this is hygiene, not breakage).
+7. Drop-in find/replace of `DataViking-Tech/synth-panel` → `DataViking-Tech/althing` across README/CHANGELOG/pyproject/CONTRIBUTING/ISSUE_TEMPLATE/config.yml once the rename is executed (GitHub redirects mean this is hygiene, not breakage).
8. Fill in GitHub repo **description** (suggested: *"Run synthetic focus groups and user research panels using AI personas. CLI tool, Python library, any LLM."* — matches pyproject `description`) and **topics** (suggested: `llm`, `synthetic-respondents`, `persona-simulation`, `user-research`, `focus-group`, `mcp-server`, `llm-evaluation`).
9. Confirm branch protection rules on main are on.
diff --git a/docs/release-dogfood-protocol.md b/docs/release-dogfood-protocol.md
index c84cbec3..13e2635f 100644
--- a/docs/release-dogfood-protocol.md
+++ b/docs/release-dogfood-protocol.md
@@ -1,11 +1,11 @@
# Release Dogfood Protocol
A cross-town convention for surfacing friction on each significant
-SynthPanel release before it hits external users.
+Althing release before it hits external users.
## Why this exists
-SynthPanel's primary surface is *other agents calling it from other
+Althing's primary surface is *other agents calling it from other
codebases*. The single-author dogfood that backs most pre-release QA
catches the failure classes that author already knows to test. It does
not catch:
@@ -39,15 +39,15 @@ filed as a normal bead without the sweep tag.
## Roles
-- **Receiving mayor** — the town that owns SynthPanel for this release
+- **Receiving mayor** — the town that owns Althing for this release
cycle (currently `jotunheim`). Bundles incoming wave reports into
- beads in the SynthPanel rig DB (the canonical store). Drops
+ beads in the Althing rig DB (the canonical store). Drops
sister-bug callouts when an incoming wave overlaps with a separately
filed local issue (e.g. yggdrasil's v1 bank-ref silent drop being a
sibling of jotunheim's MCP v3 multi-round termination — same
architectural smell, different surface).
-- **Sweeping mayors** — every other town with a SynthPanel rig runs
+- **Sweeping mayors** — every other town with a Althing rig runs
their own dogfood independently, against their own product surfaces
and use cases. Independence is the point. **Do not coordinate on
what to test before sweeping** — the divergence is the signal.
@@ -104,7 +104,7 @@ Example footer:
```
## Reporter
-yggdrasil mayor (synthpanel v1.0.4 dogfood, 2026-05-10)
+yggdrasil mayor (althing v1.0.4 dogfood, 2026-05-10)
Source-wave: hq-wisp-l4a (item 3 of 4)
```
diff --git a/docs/reproducibility.md b/docs/reproducibility.md
index 9f0bce2c..bb33a135 100644
--- a/docs/reproducibility.md
+++ b/docs/reproducibility.md
@@ -1,8 +1,8 @@
-# Reproducibility — what synthpanel can and can't promise
+# Reproducibility — what althing can and can't promise
LLM-driven research lives or dies on whether you can rerun a panel and get
the same answers. This page lays out the two reproducibility tools in
-synthpanel, what each one actually guarantees, and where the joints are.
+althing, what each one actually guarantees, and where the joints are.
## TL;DR
@@ -20,7 +20,7 @@ supplementary materials, or debugging an unexpected synthesis output.
## `--seed` — provider-aware sampling
```bash
-synthpanel panel run --seed 42 --personas p.yaml --instrument s.yaml
+althing panel run --seed 42 --personas p.yaml --instrument s.yaml
```
The seed is forwarded to the provider's sampling parameter on every
@@ -33,14 +33,14 @@ panelist call (and every synthesis call) for the duration of the run.
| OpenAI / OpenRouter | Forwarded as `seed` on the chat-completions request |
| Gemini (Google) | Forwarded as `seed` on the OpenAI-compatible endpoint |
| xAI (Grok) | Forwarded as `seed` |
-| Anthropic (Claude) | **Not supported.** synthpanel logs a single warning per provider per run and proceeds without determinism |
+| Anthropic (Claude) | **Not supported.** althing logs a single warning per provider per run and proceeds without determinism |
| Local / unknown OpenAI-compatible | Forwarded; whether it's honored depends on the runtime |
### Why Claude isn't reproducible via `--seed`
Anthropic's Messages API has no `seed` parameter at the time of writing.
Setting one would mislead users into thinking determinism holds. Instead,
-synthpanel:
+althing:
1. Logs **one** warning per provider per run, naming the provider:
```
@@ -92,7 +92,7 @@ When `--seed` is set, the value lands in two places in the output JSON:
## `--resume` — replay an existing run
```bash
-synthpanel panel run --resume
+althing panel run --resume
```
`--resume` operates on a checkpoint written by a prior `panel run` (with
@@ -102,7 +102,7 @@ remaining panelists are dispatched to the provider.
This **is** byte-deterministic for the already-completed slice — the
responses are served from the checkpoint, not regenerated. Combined with
-`--seed N` on the resumed slice, you get the closest synthpanel offers
+`--seed N` on the resumed slice, you get the closest althing offers
to a fully deterministic run on supporting providers.
### Drift detection
diff --git a/docs/response-contract.md b/docs/response-contract.md
index 42f803ef..b484bab0 100644
--- a/docs/response-contract.md
+++ b/docs/response-contract.md
@@ -1,7 +1,7 @@
# Response Contract — v1.0.0
The canonical reference for `panel_verdict.json`, the closed `flags[]` enum, and
-the typed error envelope. Schema source of truth: [`synthpanel/schemas/v1.0.0.json`](../src/synth_panel/schemas/v1.0.0.json),
+the typed error envelope. Schema source of truth: [`althing/schemas/v1.0.0.json`](../src/althing/schemas/v1.0.0.json),
embedded in the package — no remote URL, no DNS dependency.
> **Audience:** consuming-agent authors. If you call `run_panel`,
@@ -13,23 +13,23 @@ embedded in the package — no remote URL, no DNS dependency.
```mermaid
sequenceDiagram
participant Agent
- participant SynthPanel as run_panel
+ participant Althing as run_panel
participant Orchestrator
participant Model
- Agent->>SynthPanel: run_panel(decision_being_informed=...)
- SynthPanel->>SynthPanel: grace shim (AC-4) + validate request (pre-model)
+ Agent->>Althing: run_panel(decision_being_informed=...)
+ Althing->>Althing: grace shim (AC-4) + validate request (pre-model)
alt omitted (v1.0.x grace window)
- SynthPanel->>SynthPanel: synthesize "unspecified-legacy-call" + W_DECISION_MISSING warning
- else omitted (SYNTHPANEL_SCHEMA_MIN >= 1.1.0)
- SynthPanel-->>Agent: error_envelope (MISSING_DECISION)
+ Althing->>Althing: synthesize "unspecified-legacy-call" + W_DECISION_MISSING warning
+ else omitted (ALTHING_SCHEMA_MIN >= 1.1.0)
+ Althing-->>Agent: error_envelope (MISSING_DECISION)
else empty / <12 / >280 / newline / wrong type
- SynthPanel-->>Agent: error_envelope (MISSING_DECISION | INVALID_TOOL_ARG | DECISION_TOO_LONG)
+ Althing-->>Agent: error_envelope (MISSING_DECISION | INVALID_TOOL_ARG | DECISION_TOO_LONG)
else valid
- SynthPanel->>Orchestrator: dispatch panel
+ Althing->>Orchestrator: dispatch panel
Orchestrator->>Model: panelist turns
Model-->>Orchestrator: structured responses
- alt 3-strike retry exhausted (haiku) AND SYNTHPANEL_DRIFT_DEGRADE=1
+ alt 3-strike retry exhausted (haiku) AND ALTHING_DRIFT_DEGRADE=1
Orchestrator-->>Agent: panel_verdict { flags: [{schema_drift, warn}] }
else 3-strike exhausted (default v1.0)
Orchestrator-->>Agent: error_envelope (SCHEMA_DRIFT, retry_safe=true)
@@ -40,7 +40,7 @@ sequenceDiagram
end
```
-`SYNTHPANEL_DRIFT_DEGRADE` is **off by default in v1.0.0** (typed error on
+`ALTHING_DRIFT_DEGRADE` is **off by default in v1.0.0** (typed error on
exhaustion) and **on by default in v1.1.0** (degraded artifact with
`schema_drift` flag). See [docs/migration-v1.md](migration-v1.md) for the grace
window.
@@ -55,7 +55,7 @@ yet. The server synthesizes the placeholder `"unspecified-legacy-call"`,
returns a `W_DECISION_MISSING` nudge in the response `warnings[]`, and the
placeholder flows through persistence and the verdict echo exactly like a
real value — so audits can identify legacy traffic. Setting
-`SYNTHPANEL_SCHEMA_MIN=1.1.0` (v1.1.0 default) turns omission into a hard
+`ALTHING_SCHEMA_MIN=1.1.0` (v1.1.0 default) turns omission into a hard
typed `MISSING_DECISION` reject. A field that is *provided* but
empty/whitespace is a caller bug, not legacy traffic — it is rejected with
`MISSING_DECISION` in every version.
@@ -146,7 +146,7 @@ and structured-output engine surface signals; orchestrator decides.
| `persona_collision` | Duplicate/near-duplicate personas inflated agreement | Cosine similarity > 0.92 across ≥ 2 personas |
| `out_of_distribution` | Stimulus outside training/persona coverage | Retrieval confidence below floor |
| `refusal_or_degenerate` | One or more personas refused or returned empty/boilerplate | Parser-level detection |
-| `schema_drift` | Degraded artifact returned after 3-strike retry exhaustion | Only fires when `SYNTHPANEL_DRIFT_DEGRADE=1` (default v1.1.0) |
+| `schema_drift` | Degraded artifact returned after 3-strike retry exhaustion | Only fires when `ALTHING_DRIFT_DEGRADE=1` (default v1.1.0) |
### Severity
@@ -221,7 +221,7 @@ elif verdict["convergence"] >= 0.7:
| Code | When | `retry_safe` |
|---|---|---|
-| `MISSING_DECISION` | Required field omitted (hard-reject mode, `SYNTHPANEL_SCHEMA_MIN>=1.1.0`) or provided but empty after trim | `false` |
+| `MISSING_DECISION` | Required field omitted (hard-reject mode, `ALTHING_SCHEMA_MIN>=1.1.0`) or provided but empty after trim | `false` |
| `DECISION_TOO_LONG` | `>280` chars after trim | `false` |
| `INVALID_TOOL_ARG` | Other request validation failure — including `<12` chars after trim, newlines, or a non-string value | `false` |
| `INVALID_FLAG` | Response carries a flag not in the closed enum | `false` |
@@ -264,7 +264,7 @@ Fail fast, fail closed.
## Schema asset
Single file, embedded in the package:
-[`synthpanel/schemas/v1.0.0.json`](../src/synth_panel/schemas/v1.0.0.json).
+[`althing/schemas/v1.0.0.json`](../src/althing/schemas/v1.0.0.json).
Append-only — new contract versions ship as parallel files
(`v1.1.0.json`, `v2.0.0.json`), never as in-place edits. One documented
exception: v1.0.6 appended `PANEL_TIMEOUT` to `error_codes_enum` to record a
diff --git a/docs/site-audit-2026-04-30.md b/docs/site-audit-2026-04-30.md
index b5dbb580..31fdd153 100644
--- a/docs/site-audit-2026-04-30.md
+++ b/docs/site-audit-2026-04-30.md
@@ -1,4 +1,4 @@
-# Site Audit: synthpanel.dev vs CLI Surface
+# Site Audit: althing.dev vs CLI Surface
**Date:** 2026-04-30
**CLI version audited:** 0.12.0
@@ -19,27 +19,27 @@ site/CLI sync.
| `/mcp` | `site/mcp/index.html` | ✅ Up-to-date — all 12 MCP tools documented |
| `/recommended-models` | *(missing)* | ❌ Missing — promised in 0.12.0 CHANGELOG, `docs/recommended-models.md` exists but no site page |
| `/docs/calibration` | *(missing)* | ❌ Missing — referenced in `calibration:` pack YAML output (`methodology_url`), `docs/calibration.md` exists |
-| `/blog/synthpanel-vs-commercial-alternatives.html` | `site/blog/…` | ✅ Up-to-date |
+| `/blog/althing-vs-commercial-alternatives.html` | `site/blog/…` | ✅ Up-to-date |
## CLI commands vs site coverage
### Documented on site
-- [x] `synthpanel prompt` — Quick Start snippet on `/`
-- [x] `synthpanel panel run` — Quick Start snippet on `/`
-- [x] `synthpanel report` — Quick Start snippet on `/`
-- [x] `synthpanel mcp-serve` — MCP section on `/` and full docs on `/mcp`
+- [x] `althing prompt` — Quick Start snippet on `/`
+- [x] `althing panel run` — Quick Start snippet on `/`
+- [x] `althing report` — Quick Start snippet on `/`
+- [x] `althing mcp-serve` — MCP section on `/` and full docs on `/mcp`
### Missing or undocumented
-- [ ] `synthpanel login` / `logout` / `whoami` — not mentioned anywhere (added in 0.9.x)
-- [ ] `synthpanel pack calibrate` — new in 0.12.0, not on site
-- [ ] `synthpanel pack generate` / `search` / `import` / `export` / `show` / `list` — not on site
-- [ ] `synthpanel instruments list` / `install` / `show` / `graph` — not on site
-- [ ] `synthpanel analyze` — not on site
-- [ ] `synthpanel cost summary` — not on site
-- [ ] `synthpanel panel inspect` — not on site
-- [ ] `synthpanel panel synthesize` — not on site
+- [ ] `althing login` / `logout` / `whoami` — not mentioned anywhere (added in 0.9.x)
+- [ ] `althing pack calibrate` — new in 0.12.0, not on site
+- [ ] `althing pack generate` / `search` / `import` / `export` / `show` / `list` — not on site
+- [ ] `althing instruments list` / `install` / `show` / `graph` — not on site
+- [ ] `althing analyze` — not on site
+- [ ] `althing cost summary` — not on site
+- [ ] `althing panel inspect` — not on site
+- [ ] `althing panel synthesize` — not on site
### panel run flags not documented
@@ -58,7 +58,7 @@ site/CLI sync.
## Gaps fixed in this PR (GH-318)
-- `site/index.html.j2`: Quick Start step 2 now shows `synthpanel login` as
+- `site/index.html.j2`: Quick Start step 2 now shows `althing login` as
an alternative to the env-var approach
- `site/index.html.j2`: Added `pack calibrate` to the "further features" note
below the Quick Start
@@ -77,5 +77,5 @@ See linked beads. Priority order:
4. **Advanced `panel run` flag docs** — ensemble, convergence, calibration
flags are significant features with no site coverage
5. **CI sync check** — add a GitHub Actions job that runs
- `synthpanel --help` and diffs against known coverage so drift is caught
+ `althing --help` and diffs against known coverage so drift is caught
at the PR level
diff --git a/docs/stability.md b/docs/stability.md
index dbfb7689..f0e7f536 100644
--- a/docs/stability.md
+++ b/docs/stability.md
@@ -1,6 +1,6 @@
# API Stability Policy
-synthpanel is currently **pre-1.0** (0.x.y). This document describes what contributors and users can expect about breaking changes.
+althing is currently **pre-1.0** (0.x.y). This document describes what contributors and users can expect about breaking changes.
## Pre-1.0 stance
@@ -17,10 +17,10 @@ synthpanel is currently **pre-1.0** (0.x.y). This document describes what contri
The following are considered **public** and we try hard not to break them:
-- `synth_panel.llm.providers.base.LLMProvider` — the adapter base class
+- `althing.llm.providers.base.LLMProvider` — the adapter base class
- `ProviderConfig`, `CompletionRequest`, `CompletionResponse`, `StreamEvent` — adapter contract types
-- `synth_panel.cost.lookup_pricing_by_provider(provider_string)` — returns `(ModelPricing | None, is_estimated: bool)` for synthbench-format provider strings; used by downstream cost integrations
-- `synthpanel` CLI commands (`prompt`, `panel run`, `pack list`, `instruments list|show`, etc.)
+- `althing.cost.lookup_pricing_by_provider(provider_string)` — returns `(ModelPricing | None, is_estimated: bool)` for synthbench-format provider strings; used by downstream cost integrations
+- `althing` CLI commands (`prompt`, `panel run`, `pack list`, `instruments list|show`, etc.)
- MCP tool signatures (12 tools — see [MCP docs](./mcp.md))
- Instrument YAML formats (v1 flat, v2 linear, v3 branching)
- Persona pack YAML format
@@ -29,8 +29,8 @@ The following are considered **public** and we try hard not to break them:
These may change without notice between minor versions:
-- `synth_panel.runtime.*`
-- `synth_panel.orchestrator.*` internals (the orchestrator public methods are stable; internal state is not)
-- `synth_panel.plugins.*` — plugin system is evolving
-- `synth_panel.structured.*` — structured output subsystem is evolving
+- `althing.runtime.*`
+- `althing.orchestrator.*` internals (the orchestrator public methods are stable; internal state is not)
+- `althing.plugins.*` — plugin system is evolving
+- `althing.structured.*` — structured output subsystem is evolving
- Anything not listed above as public
diff --git a/docs/structured-polling.md b/docs/structured-polling.md
index 96d4067f..e5389989 100644
--- a/docs/structured-polling.md
+++ b/docs/structured-polling.md
@@ -5,7 +5,7 @@ a liability: every `result["rounds"][0]["results"][i]["response"]`
needs prose parsing, every prose parser is a regex you'll regret, and
every regex breaks the moment a model rephrases.
-**SynthPanel has had schema-enforced polling since 0.9.8.** This page
+**Althing has had schema-enforced polling since 0.9.8.** This page
documents the path so agents stop asking panelists for "JSON in prose"
and start getting parsed, typed answers back directly. No prose
parsing. No regex. No post-hoc extraction step unless you want one.
@@ -31,9 +31,9 @@ so downstream consumers can branch on it.
The bundled JSON Schemas and matching Pydantic models live at:
-- `src/synth_panel/structured/schemas.py` — wire-format JSON Schemas
+- `src/althing/structured/schemas.py` — wire-format JSON Schemas
(`ranking`, `likert`, `yes_no`, `pick_one`, `annotated_choice`).
-- `src/synth_panel/structured/models.py` — Pydantic mirrors with
+- `src/althing/structured/models.py` — Pydantic mirrors with
tighter constraints (e.g. `Likert.rating` is constrained to 1..5).
Pass either a bundled name or an inline JSON Schema dict to
@@ -77,8 +77,8 @@ instrument:
```bash
# Export the bundled pack to a file, then run.
-synthpanel pack export product-research > /tmp/product-research.yaml
-synthpanel panel run \
+althing pack export product-research > /tmp/product-research.yaml
+althing panel run \
--personas /tmp/product-research.yaml \
--instrument positioning.yaml \
--output-format json --save
@@ -106,7 +106,7 @@ synthpanel panel run \
**Python SDK:**
```python
-from synth_panel import run_panel
+from althing import run_panel
result = run_panel(
pack_id="product-research",
@@ -123,7 +123,7 @@ result = run_panel(
**What the agent reads.** Each panelist's response is a dict with
`"structured": true`. The dict's payload key varies per model (the
JSON Schema generator names it via the schema's intent) — use the
-helper below or `synth_panel.analysis.subgroup_cli._flatten_structured_value`
+helper below or `althing.analysis.subgroup_cli._flatten_structured_value`
to unwrap to the scalar:
```python
@@ -162,15 +162,15 @@ instrument:
```
```bash
-synthpanel pack export ai-eval-buyers > /tmp/ai-eval-buyers.yaml
-synthpanel panel run --personas /tmp/ai-eval-buyers.yaml --instrument nps.yaml \
+althing pack export ai-eval-buyers > /tmp/ai-eval-buyers.yaml
+althing panel run --personas /tmp/ai-eval-buyers.yaml --instrument nps.yaml \
--output-format json --save
```
The agent unwraps each `response` dict (`score`/`rating`/`value` key)
and computes the mean in one line. Or — for the canonical aggregate —
-run `synthpanel analyze --output json`, which calls
-`synth_panel.analysis.distribution.distribution_for_question()` and
+run `althing analyze --output json`, which calls
+`althing.analysis.distribution.distribution_for_question()` and
returns:
```jsonc
@@ -226,7 +226,7 @@ instrument:
```
Each panelist returns a list (`["hallucination", "cost-unpredictable"]`).
-`synthpanel analyze` aggregates per tag, zero-filling unmentioned
+`althing analyze` aggregates per tag, zero-filling unmentioned
taxonomy entries plus a bucket for off-taxonomy `other` themes so the
agent can rank risks by mentions without parsing prose.
@@ -277,7 +277,7 @@ instrument:
```
```bash
-synthpanel panel run \
+althing panel run \
--personas /tmp/product-research.yaml \
--instrument ranking.yaml \
--extract-schema ranking \
@@ -312,10 +312,10 @@ The bundled persona packs ship 15–20 personas each. For 35 personas,
merge `product-research` (20) with `ai-eval-buyers` (15) at the CLI:
```bash
-synthpanel pack export product-research > /tmp/product-research.yaml
-synthpanel pack export ai-eval-buyers > /tmp/ai-eval-buyers.yaml
+althing pack export product-research > /tmp/product-research.yaml
+althing pack export ai-eval-buyers > /tmp/ai-eval-buyers.yaml
-synthpanel panel run \
+althing panel run \
--personas /tmp/product-research.yaml \
--personas-merge /tmp/ai-eval-buyers.yaml \
--instrument prioritize.yaml \
@@ -374,10 +374,10 @@ not a *last* step.
Two equivalent paths. Pick whichever fits your agent runtime.
-**(a) `synthpanel analyze` — let the package do it for you.**
+**(a) `althing analyze` — let the package do it for you.**
```bash
-synthpanel analyze --output json > analysis.json
+althing analyze --output json > analysis.json
```
`analysis.json` contains a `distribution_by_question` block with per-
@@ -390,7 +390,7 @@ has the panel result in memory (e.g. from an MCP `run_panel` call),
import the same routines the CLI uses:
```python
-from synth_panel.analysis import distribution_for_question
+from althing.analysis import distribution_for_question
# Q0 (enum) — pick-one
q0_responses = [
@@ -410,11 +410,11 @@ winner = max(q0_dist["frequencies"], key=q0_dist["frequencies"].get)
`_unwrap_structured(response_dict, question_id, schema_type)` peels
the per-panelist record down to the scalar/list the distribution
function expects — see the helper in
-`src/synth_panel/analysis/subgroup_cli.py`.
+`src/althing/analysis/subgroup_cli.py`.
### Stable JSON output for agents
-The `distribution_by_question` block (from `synthpanel analyze`) and
+The `distribution_by_question` block (from `althing analyze`) and
the per-panelist `response` field (when `response_schema` is set) are
the schema-stable parts of the payload. They are:
@@ -448,7 +448,7 @@ def tag_ranking(dist: dict) -> list[tuple[str, int]]:
## CLI shortcut — there isn't one (yet)
-There is no `synthpanel poll run --choices A,B,C` wrapper command
+There is no `althing poll run --choices A,B,C` wrapper command
today. The equivalent is a tiny instrument YAML — usually one block —
plus the standard `panel run`:
@@ -463,7 +463,7 @@ instrument:
type: enum
options: ["A", "B", "C", "D"]
YAML
-synthpanel panel run \
+althing panel run \
--personas /tmp/product-research.yaml \
--instrument /tmp/positioning.yaml \
--output-format json --save
@@ -477,7 +477,7 @@ instrument:
response_schema:
type: text
YAML
-synthpanel panel run \
+althing panel run \
--personas /tmp/product-research.yaml \
--instrument /tmp/positioning-text.yaml \
--extract-schema pick_one \
@@ -508,7 +508,7 @@ the SDK, use `run_panel` with a one-question `instrument` dict.
- **Use `extract_schema=`** to opt into one of the five bundled
Pydantic-backed schemas (`ranking`, `likert`, `yes_no`, `pick_one`,
`annotated_choice`) without authoring a JSON Schema yourself.
-- **`SYNTHPANEL_DRIFT_DEGRADE=1`** in the MCP `env` block returns a
+- **`ALTHING_DRIFT_DEGRADE=1`** in the MCP `env` block returns a
degraded `panel_verdict` with `flags: [{"code": "schema_drift", ...}]`
instead of a hard error when the 3-strike retry budget is exhausted.
Recommended for agent workflows where partial signal beats no
@@ -544,8 +544,8 @@ and you find yourself reaching for a regex over
- [docs/convergence.md](convergence.md) — auto-stop based on
bounded-question Jensen-Shannon divergence (only works with
`enum`/`scale`/`yes_no`).
-- `src/synth_panel/structured/schemas.py` — bundled JSON Schemas.
-- `src/synth_panel/structured/models.py` — Pydantic mirrors.
-- `src/synth_panel/instrument.py` — `response_schema` validator.
-- `src/synth_panel/analysis/distribution.py` — deterministic per-
- question distributions used by `synthpanel analyze`.
+- `src/althing/structured/schemas.py` — bundled JSON Schemas.
+- `src/althing/structured/models.py` — Pydantic mirrors.
+- `src/althing/instrument.py` — `response_schema` validator.
+- `src/althing/analysis/distribution.py` — deterministic per-
+ question distributions used by `althing analyze`.
diff --git a/docs/synthbench-integration.md b/docs/synthbench-integration.md
index 93b0f81b..216260a0 100644
--- a/docs/synthbench-integration.md
+++ b/docs/synthbench-integration.md
@@ -2,7 +2,7 @@
SynthBench is the public benchmark and leaderboard for measuring how
faithfully an LLM-driven panel reproduces a known human distribution.
-SynthPanel can submit a calibrated panel run directly to SynthBench at
+Althing can submit a calibrated panel run directly to SynthBench at
the end of the run with one extra flag.
This integration is **opt-in**, **gated on `--calibrate-against`**, and
@@ -11,16 +11,16 @@ ships nothing without explicit user consent.
## When you can submit
Only **calibrated** runs are submittable. SynthBench scores per-question
-JSD against a published human baseline, which SynthPanel produces only
+JSD against a published human baseline, which Althing produces only
when you pass `--calibrate-against DATASET:QUESTION` (see
[`docs/convergence.md`](convergence.md) for the calibration mechanics).
-A bare `synthpanel panel run --personas ... --topic "pricing"` is
+A bare `althing panel run --personas ... --topic "pricing"` is
qualitative output and has no SynthBench score to submit. The CLI
hard-fails at parse time if you try:
```bash
-$ synthpanel panel run ... --submit-to-synthbench
+$ althing panel run ... --submit-to-synthbench
Error: --submit-to-synthbench requires --calibrate-against. Only
calibrated runs produce a SynthBench-shaped score; bare panel runs
cannot be submitted to the leaderboard.
@@ -33,7 +33,7 @@ cannot be submitted to the leaderboard.
export SYNTHBENCH_API_KEY=sk_synthbench_...
# 2. Run a calibrated panel and submit at completion.
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument happiness-probe \
--calibrate-against gss:HAPPY \
@@ -42,12 +42,12 @@ synthpanel panel run \
```
First-time use prints a one-screen consent block; accept with `y`. The
-acceptance is recorded at `~/.synthpanel/synthbench-consent.json` so
+acceptance is recorded at `~/.althing/synthbench-consent.json` so
subsequent runs do not re-prompt. For CI pass `--yes` to bypass the
prompt:
```bash
-synthpanel panel run \
+althing panel run \
--personas ./ci-personas.yaml \
--instrument happiness-probe \
--calibrate-against gss:HAPPY \
@@ -74,7 +74,7 @@ Per the consent notice:
* The calibration spec (e.g. `gss:HAPPY`), extractor label, and panel
sample size *n*.
* Run config: model identifier(s), persona pack name, instrument name.
-* The SynthPanel client version.
+* The Althing client version.
## Payload contract
@@ -88,11 +88,11 @@ see SynthBench's `SUBMISSIONS.md`). Concretely:
"version": "0.1.0",
"config": {
"dataset": "gss",
- "provider": "synthpanel/claude-haiku-4-5-20251001",
- "framework": "synthpanel",
+ "provider": "althing/claude-haiku-4-5-20251001",
+ "framework": "althing",
"calibration_spec": "gss:HAPPY",
"n": 60,
- "client": "synthpanel",
+ "client": "althing",
"client_version": "1.5.7",
"panelist_model": "claude-haiku-4-5-20251001",
"instrument": "happiness-probe",
@@ -130,7 +130,7 @@ Contract notes:
payload targets (`synthbench.__version__` when the harness is
importable).
* `config.dataset` is the `DATASET` half of the calibration spec;
- `config.provider` uses SynthBench's `synthpanel/` provider
+ `config.provider` uses SynthBench's `althing/` provider
format so leaderboard rows classify under the *product* framework.
* `jsd` and `kendall_tau` are computed from the exact distributions in
the payload using SynthBench's own metric functions (base-2 JSD,
@@ -188,7 +188,7 @@ reason. Surface that to the SynthBench team if it persists across runs.
## Privacy + consent record
-Consent is stored as JSON at `~/.synthpanel/synthbench-consent.json`:
+Consent is stored as JSON at `~/.althing/synthbench-consent.json`:
```json
{
@@ -217,5 +217,5 @@ SynthBench-side development. Both env vars match the names the
* [`docs/convergence.md`](convergence.md) — the calibration / JSD
mechanics that produce the score this integration uploads.
-* `synth_panel.synthbench_submit` — the implementation, including the
+* `althing.synthbench_submit` — the implementation, including the
payload transformer and HTTP transport.
diff --git a/docs/task-recommendations.md b/docs/task-recommendations.md
index cf40993d..29db4dd1 100644
--- a/docs/task-recommendations.md
+++ b/docs/task-recommendations.md
@@ -19,7 +19,7 @@
| **AI / eval tooling discovery** | `ai-eval-buyers` (20) | `--best-model-for "Technology & Digital Life"` (SynthBench-driven) for single-model runs; `balanced-research-ensemble` for high-stakes | This audience reads benchmark numbers — match the model choice to leaderboard evidence |
| **Dev-tool feedback / technical positioning** | `developer` (15) or `startup-founder` (15) | `technical-founder-research` (`sonnet:0.4,gpt-4o:0.4,gemini-2.5-pro:0.2`) | Technical buyers detect glibness; weight toward the higher-quality families |
| **Hiring / talent / job-search messaging** | `recruiters-talent` (15) for employer-side, `job-seekers` (15) for candidate-side | `fast-cheap-preflight` for shape → `balanced-research-ensemble` for finals | Two distinct audiences — don't pool them; run separate panels |
-| **Healthcare messaging / patient comms** | `healthcare-patient` (15) | `balanced-research-ensemble` by default; **never single-model for clinical/compliance** copy | Stakes are high; ensemble + `synthpanel report` + human SME review is the floor |
+| **Healthcare messaging / patient comms** | `healthcare-patient` (15) | `balanced-research-ensemble` by default; **never single-model for clinical/compliance** copy | Stakes are high; ensemble + `althing report` + human SME review is the floor |
| **Education / student outreach** | `students` (15) | `fast-cheap-preflight` for early loops; `consumer-mass-appeal` weighted split for finals | Age-skewed audience; the weighted split keeps cost down |
| **Founder / early-stage hypothesis testing** | `startup-founder` (15) | `fast-cheap-preflight` is enough until you're charging money | Founders forgive directional answers; save the ensemble budget for paying-customer questions |
| **Pre-launch / board-deck / go-no-go** | Audience-appropriate pack (above) | `high-stakes-validation` 4-way ensemble + `--blend` | The one place you *should* spend on the full ensemble + blend |
@@ -88,8 +88,8 @@ pack name); the MCP / SDK surfaces accept the pack name directly.
### Product positioning — fast iteration
```bash
-synthpanel pack export product-research > /tmp/product-research.yaml
-synthpanel panel run \
+althing pack export product-research > /tmp/product-research.yaml
+althing panel run \
--personas /tmp/product-research.yaml \
--instrument /tmp/positioning.yaml \
--model haiku \
@@ -112,7 +112,7 @@ synthpanel panel run \
### Product positioning — pre-publication ensemble
```bash
-synthpanel panel run \
+althing panel run \
--personas /tmp/product-research.yaml \
--instrument /tmp/positioning.yaml \
--models 'haiku,sonnet,gemini-2.5-flash' \
@@ -135,8 +135,8 @@ synthpanel panel run \
### Enterprise GTM — skeptical ensemble
```bash
-synthpanel pack export skeptical-executives > /tmp/skeptical-executives.yaml
-synthpanel panel run \
+althing pack export skeptical-executives > /tmp/skeptical-executives.yaml
+althing panel run \
--personas /tmp/skeptical-executives.yaml \
--instrument /tmp/gtm-pitch.yaml \
--models 'sonnet,gpt-4o,gemini-2.5-pro' \
@@ -160,8 +160,8 @@ synthpanel panel run \
### Trust / credibility audit — hostile audience
```bash
-synthpanel pack export market-research-critics > /tmp/market-research-critics.yaml
-synthpanel panel run \
+althing pack export market-research-critics > /tmp/market-research-critics.yaml
+althing panel run \
--personas /tmp/market-research-critics.yaml \
--instrument /tmp/methodology-claim.yaml \
--models 'sonnet,gpt-4o,gemini-2.5-pro' \
@@ -172,8 +172,8 @@ synthpanel panel run \
### AI / eval discovery — SynthBench-guided single model
```bash
-synthpanel pack export ai-eval-buyers > /tmp/ai-eval-buyers.yaml
-synthpanel panel run \
+althing pack export ai-eval-buyers > /tmp/ai-eval-buyers.yaml
+althing panel run \
--personas /tmp/ai-eval-buyers.yaml \
--instrument /tmp/eval-tool-positioning.yaml \
--best-model-for "Technology & Digital Life" \
@@ -188,15 +188,15 @@ topic and prints its choice to stderr before the run (see
### Healthcare patient messaging — ensemble + report
```bash
-synthpanel pack export healthcare-patient > /tmp/healthcare-patient.yaml
-synthpanel panel run \
+althing pack export healthcare-patient > /tmp/healthcare-patient.yaml
+althing panel run \
--personas /tmp/healthcare-patient.yaml \
--instrument /tmp/patient-comms.yaml \
--models 'sonnet,gpt-4o,gemini-2.5-pro' \
--blend \
--save --output-format json \
| jq -r '.result_id' \
-| xargs synthpanel report --output patient-comms-panel.md
+| xargs althing report --output patient-comms-panel.md
```
> **Never run healthcare comms on a single cheap model.** Use the
@@ -210,13 +210,13 @@ panels; pooling them dilutes the signal.
```bash
# Employer side
-synthpanel pack export recruiters-talent > /tmp/recruiters-talent.yaml
-synthpanel panel run --personas /tmp/recruiters-talent.yaml \
+althing pack export recruiters-talent > /tmp/recruiters-talent.yaml
+althing panel run --personas /tmp/recruiters-talent.yaml \
--instrument /tmp/hiring-pitch.yaml --model haiku --save --output-format json
# Candidate side
-synthpanel pack export job-seekers > /tmp/job-seekers.yaml
-synthpanel panel run --personas /tmp/job-seekers.yaml \
+althing pack export job-seekers > /tmp/job-seekers.yaml
+althing panel run --personas /tmp/job-seekers.yaml \
--instrument /tmp/hiring-pitch.yaml --model haiku --save --output-format json
```
@@ -255,9 +255,9 @@ calibration step that closes the loop.
The convenience flags the upstream issue floats —
```bash
-synthpanel pack list --recommend
-synthpanel models recommend --task positioning
-synthpanel recommend --task enterprise-gtm
+althing pack list --recommend
+althing models recommend --task positioning
+althing recommend --task enterprise-gtm
```
— **do not exist yet.** This page is the agent-facing surface for
diff --git a/docs/traitprint-local-signoff.md b/docs/traitprint-local-signoff.md
index 69d5d775..b47f00aa 100644
--- a/docs/traitprint-local-signoff.md
+++ b/docs/traitprint-local-signoff.md
@@ -1,6 +1,6 @@
# Traitprint Local — CPO Sign-off
-**Author:** cpo (synthpanel)
+**Author:** cpo (althing)
**Date:** 2026-04-19
**Requested by:** mayor/
**Subject:** Sign-off on Traitprint Local — open-source local-first vault with optional cloud sync
@@ -81,7 +81,7 @@ pip install traitprint # Everything. Vault + CLI + MCP + sync client.
The cloud sync commands (`traitprint push`, `traitprint pull`, `traitprint
auth login`) **ship in the base package but truly no-op without an API
key set**. If you want an extras-gated variant later for heavy optional
-deps, use the `synthpanel[mcp]` pattern — but only when there's an
+deps, use the `althing[mcp]` pattern — but only when there's an
actual dependency weight argument. Today there isn't one; `httpx` is
already in the tree.
@@ -123,7 +123,7 @@ formalizes what is already derivable.
### D. Support burden
Real. Budget **~1 engineer-day per week** for GitHub issues + PR
-review once any community forms. Copy the synthpanel `CONTRIBUTING.md`
+review once any community forms. Copy the althing `CONTRIBUTING.md`
/ `CODE_OF_CONDUCT.md` / issue templates verbatim.
### What we must NOT open-source
@@ -151,7 +151,7 @@ These stay server-side, period:
## 4. Does the demo flow work for Miami?
-**Yes, it works — and it works *because* SynthPanel already
+**Yes, it works — and it works *because* Althing already
established the `pip install → mcp-serve → Claude connects` rhythm
for this audience tonight.**
@@ -170,7 +170,7 @@ the current cloud-only Traitprint.
### Why this lands for Miami specifically
-1. **Echoes the SynthPanel demo beat-for-beat.** Same host, same
+1. **Echoes the Althing demo beat-for-beat.** Same host, same
command shape, same time budget. The audience sees a pattern and
concludes DataViking is a *platform*, not three products.
2. **Pre-empts the "needs a cloud?" objection** before it's asked.
@@ -182,7 +182,7 @@ the current cloud-only Traitprint.
- `traitprint init` must complete in **<5 seconds** cold.
- Local mode must work with **zero API keys set** (including no LLM
- key — use MCP sampling in the host, same pattern as SynthPanel's
+ key — use MCP sampling in the host, same pattern as Althing's
`sp-6at`).
- MCP tool names must read well in a Claude tool-call log (short,
descriptive, no `cloud_*` prefix on local tools).
@@ -217,7 +217,7 @@ lead-gen mechanism, not a risk.
one.** Signal evolvability.
5. **Demo flow tested end-to-end on a clean laptop before any
public-facing use.** No cold-start at the booth.
-6. **Copy the SynthPanel `LICENSE` / `CONTRIBUTING.md` /
+6. **Copy the Althing `LICENSE` / `CONTRIBUTING.md` /
`CODE_OF_CONDUCT.md` / issue templates.** We already wrote them;
reuse.
7. **README makes the cloud upgrade path visible, not hidden.** Lead
@@ -232,9 +232,9 @@ lead-gen mechanism, not a risk.
- **Announce Traitprint Local as part of the Miami booth handout**,
not the stage demo. "Scan this QR, get early access." Captures emails
without demo risk.
-- **Wire Traitprint's local MCP tools to interop with SynthPanel's
+- **Wire Traitprint's local MCP tools to interop with Althing's
persona format** as a downstream stretch goal. A Traitprint vault
- can become a SynthPanel persona definition. That's the DataViking
+ can become a Althing persona definition. That's the DataViking
platform story made literal.
- **Instrument the local → cloud conversion funnel** before first
release. Without telemetry, you cannot answer the dilution question
diff --git a/docs/vscode-extension-decision.md b/docs/vscode-extension-decision.md
index 6e74d987..894f0451 100644
--- a/docs/vscode-extension-decision.md
+++ b/docs/vscode-extension-decision.md
@@ -20,14 +20,14 @@ than Q3 2026, and only if the revisit triggers below fire.
VS Code AI Toolkit shipped first-class MCP support in March 2026. Any
VS Code user running Claude Code, Cursor, Copilot, or the AI Toolkit can
-point their editor at `synthpanel mcp-serve` and get all 12 SynthPanel
+point their editor at `althing mcp-serve` and get all 12 Althing
tools natively. A custom extension cannot improve on that for tool
invocation — it can only add GUI surface.
### 2. The GUI surface is nice-to-have, not adoption-blocking
A dedicated extension would offer: persona-card editing, instrument flow
-preview (Mermaid already works in the terminal via `synthpanel instruments
+preview (Mermaid already works in the terminal via `althing instruments
graph`), and result visualization panels. These are quality-of-life
improvements for power users, not the thing gating agent-framework adoption.
The top 3 unfiled gaps (Python SDK, framework examples, Composio) each
diff --git a/examples/README.md b/examples/README.md
index 38beb569..42ac9398 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,4 +1,4 @@
-# synthpanel examples
+# althing examples
Drop-in YAML files for getting started. Pair any persona pack with any
instrument pack — the CLI takes both as separate `--personas` and
@@ -33,7 +33,7 @@ schema demo. Use these as starting points for your own studies.
The `instruments/` subdirectory holds three additional standalone
instrument files (`general_survey.yaml`, `market_research.yaml`,
`product_feedback.yaml`) kept for backward compatibility. Prefer the
-bundled packs (`synthpanel instruments list`) for new work.
+bundled packs (`althing instruments list`) for new work.
## Showing panelists images, web pages, or HTML
@@ -47,37 +47,37 @@ full attachment-type reference.
```bash
# v1: single round, flat questions
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/survey.yaml
# v2: linear multi-round
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/multi-round-study.yaml
# v3: branching — pricing segmentation
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/pricing-segmentation-study.yaml
# v3: branching — A/B concept test
-synthpanel panel run \
+althing panel run \
--personas examples/personas.yaml \
--instrument examples/concept-test-ab.yaml
# Industry-specific: SaaS onboarding friction (v2)
-synthpanel panel run \
+althing panel run \
--personas examples/saas-onboarding-friction/personas.yaml \
--instrument examples/saas-onboarding-friction/instrument.yaml
# Industry-specific: developer tools pricing (v3 branching)
-synthpanel panel run \
+althing panel run \
--personas examples/devtools-pricing/personas.yaml \
--instrument examples/devtools-pricing/instrument.yaml
# Industry-specific: consumer name test (v1)
-synthpanel panel run \
+althing panel run \
--personas examples/consumer-name-test/personas.yaml \
--instrument examples/consumer-name-test/instrument.yaml
```
@@ -90,23 +90,23 @@ The 14 bundled packs cover most common audiences:
```bash
# Pressure-test pricing on AI/ML buyers
-synthpanel panel run --personas ai-eval-buyers --instrument pricing-discovery
+althing panel run --personas ai-eval-buyers --instrument pricing-discovery
# Read your positioning against a hostile senior-buyer audience
-synthpanel panel run --personas skeptical-executives --instrument landing-page-comprehension
+althing panel run --personas skeptical-executives --instrument landing-page-comprehension
# Stress-test methodology claims against professional skeptics
-synthpanel panel run --personas market-research-critics --instrument general-survey
+althing panel run --personas market-research-critics --instrument general-survey
# Broad gut-check across a wide professional cross-section
-synthpanel panel run --personas broad-professionals --instrument name-test
+althing panel run --personas broad-professionals --instrument name-test
# Enterprise AI procurement framing check
-synthpanel panel run --personas enterprise-ai-buyers --instrument feature-prioritization
+althing panel run --personas enterprise-ai-buyers --instrument feature-prioritization
```
-Run `synthpanel pack list` to see every installed pack and its persona
-count, or `synthpanel pack show ` to inspect personas before
+Run `althing pack list` to see every installed pack and its persona
+count, or `althing pack show ` to inspect personas before
running. The [main README](../README.md#builtin-persona-packs-14-232-personas-total)
lists every bundled pack with one-line audience summaries.
@@ -115,15 +115,15 @@ lists every bundled pack with one-line audience summaries.
Render the round DAG to sanity-check routing before you spend tokens:
```bash
-synthpanel instruments graph examples/pricing-segmentation-study.yaml --format mermaid
-synthpanel instruments graph examples/concept-test-ab.yaml --format mermaid
+althing instruments graph examples/pricing-segmentation-study.yaml --format mermaid
+althing instruments graph examples/concept-test-ab.yaml --format mermaid
```
Validate a file without running it (parse-only — fails on bad DAGs,
missing `else` clauses, unreachable rounds, etc.):
```bash
-synthpanel instruments install examples/concept-test-ab.yaml --name concept-test-ab
+althing instruments install examples/concept-test-ab.yaml --name concept-test-ab
```
`install` parses the file through the full v3 validator before writing
diff --git a/examples/consumer-name-test/README.md b/examples/consumer-name-test/README.md
index 497468fe..851105a7 100644
--- a/examples/consumer-name-test/README.md
+++ b/examples/consumer-name-test/README.md
@@ -45,7 +45,7 @@ When you aggregate, expect:
## Run it
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/consumer-name-test/personas.yaml \
--instrument examples/consumer-name-test/instrument.yaml
```
@@ -61,7 +61,7 @@ to copy the instrument and edit in place:
```bash
cp examples/consumer-name-test/instrument.yaml my-name-test.yaml
# edit the {name_*} placeholders in my-name-test.yaml
-synthpanel panel run \
+althing panel run \
--personas examples/consumer-name-test/personas.yaml \
--instrument my-name-test.yaml
```
@@ -72,11 +72,11 @@ CLI version supports it; see the main README for current syntax.
## Pack substitution
For a wider 8-persona panel, swap to the bundled
-[`general-consumer.yaml`](../../src/synth_panel/packs/general-consumer.yaml)
+[`general-consumer.yaml`](../../src/althing/packs/general-consumer.yaml)
pack:
```bash
-synthpanel panel run \
+althing panel run \
--personas-pack general-consumer \
--instrument examples/consumer-name-test/instrument.yaml
```
diff --git a/examples/devtools-pricing/README.md b/examples/devtools-pricing/README.md
index 2b361c1d..f702a9e0 100644
--- a/examples/devtools-pricing/README.md
+++ b/examples/devtools-pricing/README.md
@@ -54,7 +54,7 @@ You get four kinds of signal:
## Run it
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/devtools-pricing/personas.yaml \
--instrument examples/devtools-pricing/instrument.yaml
```
@@ -62,25 +62,25 @@ synthpanel panel run \
Render the routing graph (4-way branch from discovery):
```bash
-synthpanel instruments graph \
+althing instruments graph \
examples/devtools-pricing/instrument.yaml --format mermaid
```
Validate without running (catches DAG / theme issues):
```bash
-synthpanel instruments install \
+althing instruments install \
examples/devtools-pricing/instrument.yaml --name devtools-pricing-test
```
## Pack substitution
-The bundled [`developer.yaml`](../../src/synth_panel/packs/developer.yaml)
+The bundled [`developer.yaml`](../../src/althing/packs/developer.yaml)
pack covers similar ground with 16 personas spanning a wider stack.
For richer breadth:
```bash
-synthpanel panel run \
+althing panel run \
--personas-pack developer \
--instrument examples/devtools-pricing/instrument.yaml
```
diff --git a/examples/instruments/general_survey.yaml b/examples/instruments/general_survey.yaml
index c73ad063..75c1a3c1 100644
--- a/examples/instruments/general_survey.yaml
+++ b/examples/instruments/general_survey.yaml
@@ -1,10 +1,10 @@
# general_survey: broad opinion survey for smoke-testing panel setups.
#
# Usage:
-# synthpanel panel run --personas examples/personas.yaml --instrument examples/instruments/general_survey.yaml
+# althing panel run --personas examples/personas.yaml --instrument examples/instruments/general_survey.yaml
#
# This is also available as a bundled pack (no file path needed):
-# synthpanel panel run --personas examples/personas.yaml --instrument general-survey
+# althing panel run --personas examples/personas.yaml --instrument general-survey
instrument:
version: 3
rounds:
diff --git a/examples/instruments/market_research.yaml b/examples/instruments/market_research.yaml
index 63861b7c..ae069ff7 100644
--- a/examples/instruments/market_research.yaml
+++ b/examples/instruments/market_research.yaml
@@ -1,10 +1,10 @@
# market_research: competitive preference, purchase intent, pricing sensitivity.
#
# Usage:
-# synthpanel panel run --personas examples/personas.yaml --instrument examples/instruments/market_research.yaml --var problem="expense tracking"
+# althing panel run --personas examples/personas.yaml --instrument examples/instruments/market_research.yaml --var problem="expense tracking"
#
# Also available as a bundled pack:
-# synthpanel panel run --personas examples/personas.yaml --instrument market-research --var problem="expense tracking"
+# althing panel run --personas examples/personas.yaml --instrument market-research --var problem="expense tracking"
instrument:
version: 3
rounds:
diff --git a/examples/instruments/product_feedback.yaml b/examples/instruments/product_feedback.yaml
index d2738a17..77c2d628 100644
--- a/examples/instruments/product_feedback.yaml
+++ b/examples/instruments/product_feedback.yaml
@@ -1,10 +1,10 @@
# product_feedback: NPS + feature satisfaction + open-ended follow-up.
#
# Usage:
-# synthpanel panel run --personas examples/personas.yaml --instrument examples/instruments/product_feedback.yaml --var product="Acme Widget"
+# althing panel run --personas examples/personas.yaml --instrument examples/instruments/product_feedback.yaml --var product="Acme Widget"
#
# Also available as a bundled pack:
-# synthpanel panel run --personas examples/personas.yaml --instrument product-feedback --var product="Acme Widget"
+# althing panel run --personas examples/personas.yaml --instrument product-feedback --var product="Acme Widget"
instrument:
version: 3
rounds:
diff --git a/examples/instruments/with-attachments.yaml b/examples/instruments/with-attachments.yaml
index 15776b11..6e2e190a 100644
--- a/examples/instruments/with-attachments.yaml
+++ b/examples/instruments/with-attachments.yaml
@@ -3,7 +3,7 @@
# (literal block scalar inline).
#
# Usage:
-# synthpanel panel run --personas examples/personas.yaml --instrument examples/instruments/with-attachments.yaml
+# althing panel run --personas examples/personas.yaml --instrument examples/instruments/with-attachments.yaml
#
# The attachment bank lives at the top level of the instrument and is
# referenced from individual questions by id. Each question receives the
diff --git a/examples/integrations/README.md b/examples/integrations/README.md
index e9b4b0e4..08a849be 100644
--- a/examples/integrations/README.md
+++ b/examples/integrations/README.md
@@ -1,43 +1,43 @@
-# SynthPanel + Agent Frameworks — Works With X
+# Althing + Agent Frameworks — Works With X
-SynthPanel ships an [MCP](https://modelcontextprotocol.io) server with 12 tools
+Althing ships an [MCP](https://modelcontextprotocol.io) server with 12 tools
(`run_quick_poll`, `run_panel`, `extend_panel`, and more). Because every major
-agent framework now supports MCP as a first-class tool source, **SynthPanel
+agent framework now supports MCP as a first-class tool source, **Althing
works with all of them today — no framework-specific wrapper package
required**. The examples in this directory prove that claim end-to-end.
Each example is 15-30 lines, runs a single `run_quick_poll` demo in under 30
seconds on a fresh install, and deliberately does **not** depend on any
-SynthPanel-specific library beyond the MCP server that already ships with
-`pip install synthpanel[mcp]`.
+Althing-specific library beyond the MCP server that already ships with
+`pip install althing[mcp]`.
-> **Prerequisites for every example:** `pip install synthpanel[mcp]` and an
+> **Prerequisites for every example:** `pip install althing[mcp]` and an
> LLM API key set in your environment (`ANTHROPIC_API_KEY` by default — see
> the [Provider Configuration](../../README.md#llm-provider-support) table
-> for other providers). The `synthpanel` CLI must be on your `PATH`.
+> for other providers). The `althing` CLI must be on your `PATH`.
| File | Framework | Bridge | Install |
|------|-----------|--------|---------|
-| [openai_agents.py](openai_agents.py) | OpenAI Agents SDK | Built-in `MCPServerStdio` | `pip install openai-agents synthpanel[mcp]` |
-| [llamaindex_tool.py](llamaindex_tool.py) | LlamaIndex | `llama-index-tools-mcp` | `pip install llama-index-tools-mcp llama-index-llms-anthropic synthpanel[mcp]` |
-| [crewai_tool.py](crewai_tool.py) | CrewAI | `crewai-tools[mcp]` | `pip install "crewai-tools[mcp]" crewai synthpanel[mcp]` |
-| [langchain_tool.py](langchain_tool.py) | LangChain / LangGraph | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langgraph langchain-anthropic synthpanel[mcp]` |
-| [microsoft_agent.py](microsoft_agent.py) | Microsoft Agent Framework 1.0 | Built-in `MCPStdioTool` | `pip install agent-framework synthpanel[mcp]` |
-| [n8n_workflow.json](n8n_workflow.json) | n8n | Built-in MCP Client tool | Import into n8n + install `synthpanel[mcp]` on the runner |
-| [composio_langchain.py](composio_langchain.py) | LangChain via Composio | `synth_panel.integrations.composio` | `pip install composio composio_langchain langchain langchain-anthropic synthpanel` |
-| [composio_crewai.py](composio_crewai.py) | CrewAI via Composio | `synth_panel.integrations.composio` | `pip install composio composio_crewai crewai synthpanel` |
+| [openai_agents.py](openai_agents.py) | OpenAI Agents SDK | Built-in `MCPServerStdio` | `pip install openai-agents althing[mcp]` |
+| [llamaindex_tool.py](llamaindex_tool.py) | LlamaIndex | `llama-index-tools-mcp` | `pip install llama-index-tools-mcp llama-index-llms-anthropic althing[mcp]` |
+| [crewai_tool.py](crewai_tool.py) | CrewAI | `crewai-tools[mcp]` | `pip install "crewai-tools[mcp]" crewai althing[mcp]` |
+| [langchain_tool.py](langchain_tool.py) | LangChain / LangGraph | `langchain-mcp-adapters` | `pip install langchain-mcp-adapters langgraph langchain-anthropic althing[mcp]` |
+| [microsoft_agent.py](microsoft_agent.py) | Microsoft Agent Framework 1.0 | Built-in `MCPStdioTool` | `pip install agent-framework althing[mcp]` |
+| [n8n_workflow.json](n8n_workflow.json) | n8n | Built-in MCP Client tool | Import into n8n + install `althing[mcp]` on the runner |
+| [composio_langchain.py](composio_langchain.py) | LangChain via Composio | `althing.integrations.composio` | `pip install composio composio_langchain langchain langchain-anthropic althing` |
+| [composio_crewai.py](composio_crewai.py) | CrewAI via Composio | `althing.integrations.composio` | `pip install composio composio_crewai crewai althing` |
---
## OpenAI Agents SDK
OpenAI's Agents SDK has native MCP support via `MCPServerStdio`. Wrap
-`synthpanel mcp-serve` once and every tool becomes callable.
+`althing mcp-serve` once and every tool becomes callable.
```bash
-pip install openai-agents synthpanel[mcp]
+pip install openai-agents althing[mcp]
export OPENAI_API_KEY=sk-...
-export ANTHROPIC_API_KEY=sk-... # SynthPanel's default provider
+export ANTHROPIC_API_KEY=sk-... # Althing's default provider
python openai_agents.py
```
@@ -50,7 +50,7 @@ LlamaIndex `FunctionTool` objects. Hand them to a `FunctionAgent` and you're
done.
```bash
-pip install llama-index-tools-mcp llama-index-llms-anthropic synthpanel[mcp]
+pip install llama-index-tools-mcp llama-index-llms-anthropic althing[mcp]
export ANTHROPIC_API_KEY=sk-...
python llamaindex_tool.py
```
@@ -64,7 +64,7 @@ every MCP tool look like a native CrewAI tool. Pass the list straight into the
`Agent(tools=...)` argument.
```bash
-pip install "crewai-tools[mcp]" crewai synthpanel[mcp]
+pip install "crewai-tools[mcp]" crewai althing[mcp]
export ANTHROPIC_API_KEY=sk-...
python crewai_tool.py
```
@@ -78,7 +78,7 @@ interface. The example below hands them to a LangGraph prebuilt ReAct agent,
but the same `tools` list works with any LangChain agent executor.
```bash
-pip install langchain-mcp-adapters langgraph langchain-anthropic synthpanel[mcp]
+pip install langchain-mcp-adapters langgraph langchain-anthropic althing[mcp]
export ANTHROPIC_API_KEY=sk-...
python langchain_tool.py
```
@@ -92,9 +92,9 @@ Microsoft shipped built-in MCP clients in Agent Framework 1.0 (April 2026).
`MCPServerStdio`.
```bash
-pip install agent-framework synthpanel[mcp]
+pip install agent-framework althing[mcp]
export OPENAI_API_KEY=sk-... # Agent Framework's default provider
-export ANTHROPIC_API_KEY=sk-... # SynthPanel's default provider
+export ANTHROPIC_API_KEY=sk-... # Althing's default provider
python microsoft_agent.py
```
@@ -104,41 +104,41 @@ See [microsoft_agent.py](microsoft_agent.py).
n8n's AI Agent node has a built-in **MCP Client Tool** subnode. Import
[n8n_workflow.json](n8n_workflow.json) via **Workflows → Import from File**,
-attach an Anthropic credential, and make sure `synthpanel` is on the n8n
+attach an Anthropic credential, and make sure `althing` is on the n8n
runner's `PATH`. The workflow fires `run_quick_poll` via the agent.
```bash
# on the machine running n8n:
-pip install synthpanel[mcp]
+pip install althing[mcp]
export ANTHROPIC_API_KEY=sk-...
```
## Composio (LangChain / CrewAI / Semantic Kernel / AutoGen)
Unlike the other examples in this directory, the Composio path does **not**
-go through MCP. SynthPanel ships a native [Composio
-toolkit](../../src/synth_panel/integrations/composio.py) that runs the
-SynthPanel SDK in-process, so any framework Composio supports
+go through MCP. Althing ships a native [Composio
+toolkit](../../src/althing/integrations/composio.py) that runs the
+Althing SDK in-process, so any framework Composio supports
(LangChain, CrewAI, Semantic Kernel, AutoGen, OpenAI Agents, Google ADK)
-can reach five SynthPanel actions — `quick_poll`, `run_panel`,
+can reach five Althing actions — `quick_poll`, `run_panel`,
`list_personas`, `list_instruments`, `get_panel_result` — through
`session.tools()`.
```bash
# LangChain via Composio
-pip install composio composio_langchain langchain langchain-anthropic synthpanel
+pip install composio composio_langchain langchain langchain-anthropic althing
export ANTHROPIC_API_KEY=sk-...
export COMPOSIO_API_KEY=...
python composio_langchain.py
# CrewAI via Composio (same toolkit, different provider)
-pip install composio composio_crewai crewai synthpanel
+pip install composio composio_crewai crewai althing
python composio_crewai.py
```
See [composio_langchain.py](composio_langchain.py) and
[composio_crewai.py](composio_crewai.py). The submission runbook for
-listing SynthPanel in the Composio public catalog lives at
+listing Althing in the Composio public catalog lives at
[`docs/composio-submission.md`](../../docs/composio-submission.md).
---
@@ -149,10 +149,10 @@ Every major agent framework now speaks MCP — but that fact is invisible until
someone searches for "how do I run a synthetic focus group from
<framework>?" and finds a working script. Each example is a
self-contained, indexable answer to that question and doubles as verification
-that SynthPanel's MCP bridge works end-to-end.
+that Althing's MCP bridge works end-to-end.
If your framework is not listed here and it supports MCP, the pattern is the
-same in every case: point its MCP client at `synthpanel mcp-serve` over stdio
+same in every case: point its MCP client at `althing mcp-serve` over stdio
and all 12 tools become available. If you wire up a new one, a PR adding a
sibling example here is very welcome.
diff --git a/examples/integrations/composio_crewai.py b/examples/integrations/composio_crewai.py
index bfde56c6..d00811ad 100644
--- a/examples/integrations/composio_crewai.py
+++ b/examples/integrations/composio_crewai.py
@@ -1,11 +1,11 @@
-"""SynthPanel + Composio + CrewAI.
+"""Althing + Composio + CrewAI.
-Expose SynthPanel actions to a CrewAI agent via Composio's CrewAI
-provider. The same `synthpanel_toolkit` works across Composio providers;
+Expose Althing actions to a CrewAI agent via Composio's CrewAI
+provider. The same `althing_toolkit` works across Composio providers;
only the provider object changes from the LangChain example.
Install:
- pip install composio composio_crewai crewai synthpanel
+ pip install composio composio_crewai crewai althing
Run:
export ANTHROPIC_API_KEY=sk-...
@@ -17,12 +17,12 @@
from composio_crewai import CrewAIProvider
from crewai import Agent, Crew, Task
-from synth_panel.integrations.composio import synthpanel_toolkit
+from althing.integrations.composio import althing_toolkit
def main() -> None:
composio = Composio(provider=CrewAIProvider())
- toolkit = synthpanel_toolkit(composio)
+ toolkit = althing_toolkit(composio)
session = composio.create(
user_id="researcher_1",
@@ -33,7 +33,7 @@ def main() -> None:
researcher = Agent(
role="Market Researcher",
goal="Surface honest panelist reactions to product concepts.",
- backstory="You probe AI personas via SynthPanel and distil the findings.",
+ backstory="You probe AI personas via Althing and distil the findings.",
tools=tools,
)
task = Task(
diff --git a/examples/integrations/composio_langchain.py b/examples/integrations/composio_langchain.py
index 8e2eca14..00e49c7d 100644
--- a/examples/integrations/composio_langchain.py
+++ b/examples/integrations/composio_langchain.py
@@ -1,11 +1,11 @@
-"""SynthPanel + Composio + LangChain.
+"""Althing + Composio + LangChain.
-Register SynthPanel as a Composio toolkit, then hand the resulting tools
+Register Althing as a Composio toolkit, then hand the resulting tools
to a LangChain agent. No MCP bridge, no subprocess — Composio calls the
-SynthPanel SDK in-process.
+Althing SDK in-process.
Install:
- pip install composio composio_langchain langchain langchain-anthropic synthpanel
+ pip install composio composio_langchain langchain langchain-anthropic althing
Run:
export ANTHROPIC_API_KEY=sk-...
@@ -19,12 +19,12 @@
from langchain_anthropic import ChatAnthropic
from langchain_core.prompts import ChatPromptTemplate
-from synth_panel.integrations.composio import synthpanel_toolkit
+from althing.integrations.composio import althing_toolkit
def main() -> None:
composio = Composio(provider=LangchainProvider())
- toolkit = synthpanel_toolkit(composio)
+ toolkit = althing_toolkit(composio)
session = composio.create(
user_id="researcher_1",
@@ -34,7 +34,7 @@ def main() -> None:
prompt = ChatPromptTemplate.from_messages(
[
- ("system", "You are a market research assistant. Use SynthPanel tools to poll personas."),
+ ("system", "You are a market research assistant. Use Althing tools to poll personas."),
("user", "{input}"),
("placeholder", "{agent_scratchpad}"),
]
diff --git a/examples/integrations/crewai_tool.py b/examples/integrations/crewai_tool.py
index 6146088b..53f6cfb5 100644
--- a/examples/integrations/crewai_tool.py
+++ b/examples/integrations/crewai_tool.py
@@ -1,10 +1,10 @@
-"""SynthPanel + CrewAI.
+"""Althing + CrewAI.
-Attach SynthPanel's MCP server to a CrewAI Agent via MCPServerAdapter. The
-agent gets all 12 synthpanel tools as native CrewAI tools — no wrapper code.
+Attach Althing's MCP server to a CrewAI Agent via MCPServerAdapter. The
+agent gets all 12 althing tools as native CrewAI tools — no wrapper code.
Install:
- pip install "crewai-tools[mcp]" crewai synthpanel[mcp]
+ pip install "crewai-tools[mcp]" crewai althing[mcp]
Run:
export ANTHROPIC_API_KEY=sk-...
@@ -16,14 +16,14 @@
from mcp import StdioServerParameters
-server_params = StdioServerParameters(command="synthpanel", args=["mcp-serve"])
+server_params = StdioServerParameters(command="althing", args=["mcp-serve"])
-with MCPServerAdapter(server_params) as synthpanel_tools:
+with MCPServerAdapter(server_params) as althing_tools:
researcher = Agent(
role="Synthetic Research Lead",
goal="Answer product questions via synthetic focus groups.",
- backstory="You use the synthpanel tools to poll AI personas.",
- tools=synthpanel_tools,
+ backstory="You use the althing tools to poll AI personas.",
+ tools=althing_tools,
)
task = Task(
description=(
diff --git a/examples/integrations/langchain_tool.py b/examples/integrations/langchain_tool.py
index 592fcaca..560b0dc4 100644
--- a/examples/integrations/langchain_tool.py
+++ b/examples/integrations/langchain_tool.py
@@ -1,10 +1,10 @@
-"""SynthPanel + LangChain / LangGraph.
+"""Althing + LangChain / LangGraph.
-Bridge SynthPanel's MCP tools into LangChain via langchain-mcp-adapters, then
+Bridge Althing's MCP tools into LangChain via langchain-mcp-adapters, then
hand them to a LangGraph ReAct agent. No custom tool wrappers required.
Install:
- pip install langchain-mcp-adapters langgraph langchain-anthropic synthpanel[mcp]
+ pip install langchain-mcp-adapters langgraph langchain-anthropic althing[mcp]
Run:
export ANTHROPIC_API_KEY=sk-...
@@ -21,8 +21,8 @@
async def main() -> None:
client = MultiServerMCPClient(
{
- "synthpanel": {
- "command": "synthpanel",
+ "althing": {
+ "command": "althing",
"args": ["mcp-serve"],
"transport": "stdio",
}
diff --git a/examples/integrations/llamaindex_tool.py b/examples/integrations/llamaindex_tool.py
index 8b3dc989..dc485898 100644
--- a/examples/integrations/llamaindex_tool.py
+++ b/examples/integrations/llamaindex_tool.py
@@ -1,10 +1,10 @@
-"""SynthPanel + LlamaIndex.
+"""Althing + LlamaIndex.
-Expose SynthPanel's MCP tools to a LlamaIndex FunctionAgent via the
+Expose Althing's MCP tools to a LlamaIndex FunctionAgent via the
llama-index-tools-mcp bridge. All 12 tools become callable with no wrapper code.
Install:
- pip install llama-index-tools-mcp llama-index-llms-anthropic synthpanel[mcp]
+ pip install llama-index-tools-mcp llama-index-llms-anthropic althing[mcp]
Run:
export ANTHROPIC_API_KEY=sk-...
@@ -19,14 +19,14 @@
async def main() -> None:
- mcp_client = BasicMCPClient("synthpanel", args=["mcp-serve"])
+ mcp_client = BasicMCPClient("althing", args=["mcp-serve"])
tool_spec = McpToolSpec(client=mcp_client)
tools = await tool_spec.to_tool_list_async()
agent = FunctionAgent(
tools=tools,
llm=Anthropic(model="claude-haiku-4-5"),
- system_prompt="You run synthetic focus groups via the synthpanel tools.",
+ system_prompt="You run synthetic focus groups via the althing tools.",
)
response = await agent.run(
"Run a quick_poll with three designer personas on: 'Would you pay $19/mo for an AI design critique tool?'"
diff --git a/examples/integrations/microsoft_agent.py b/examples/integrations/microsoft_agent.py
index 3f4c4127..60b788f5 100644
--- a/examples/integrations/microsoft_agent.py
+++ b/examples/integrations/microsoft_agent.py
@@ -1,10 +1,10 @@
-"""SynthPanel + Microsoft Agent Framework 1.0.
+"""Althing + Microsoft Agent Framework 1.0.
-Connect the Microsoft Agent Framework's built-in MCP client to SynthPanel's
+Connect the Microsoft Agent Framework's built-in MCP client to Althing's
stdio server. The framework shipped MCP support in version 1.0 (April 2026).
Install:
- pip install agent-framework synthpanel[mcp]
+ pip install agent-framework althing[mcp]
Run:
export OPENAI_API_KEY=sk-...
@@ -20,14 +20,14 @@
async def main() -> None:
async with MCPStdioTool(
- name="synthpanel",
- command="synthpanel",
+ name="althing",
+ command="althing",
args=["mcp-serve"],
- ) as synthpanel:
+ ) as althing:
agent = ChatAgent(
chat_client=OpenAIChatClient(model_id="gpt-4.1-mini"),
- instructions="Run synthetic focus groups via the synthpanel tools.",
- tools=synthpanel,
+ instructions="Run synthetic focus groups via the althing tools.",
+ tools=althing,
)
result = await agent.run(
"Use run_quick_poll with three data-scientist personas on: "
diff --git a/examples/integrations/n8n_workflow.json b/examples/integrations/n8n_workflow.json
index df8da905..108d12c7 100644
--- a/examples/integrations/n8n_workflow.json
+++ b/examples/integrations/n8n_workflow.json
@@ -1,5 +1,5 @@
{
- "name": "SynthPanel Quick Poll",
+ "name": "Althing Quick Poll",
"nodes": [
{
"parameters": {},
@@ -38,12 +38,12 @@
{
"parameters": {
"connectionType": "stdio",
- "command": "synthpanel",
+ "command": "althing",
"arguments": "mcp-serve",
"environmentVariables": "ANTHROPIC_API_KEY={{ $env.ANTHROPIC_API_KEY }}"
},
"id": "d4e5f6g7-mcp",
- "name": "SynthPanel MCP",
+ "name": "Althing MCP",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"typeVersion": 1,
"position": [620, 520]
@@ -58,7 +58,7 @@
[{ "node": "Research Agent", "type": "ai_languageModel", "index": 0 }]
]
},
- "SynthPanel MCP": {
+ "Althing MCP": {
"ai_tool": [
[{ "node": "Research Agent", "type": "ai_tool", "index": 0 }]
]
@@ -66,6 +66,6 @@
},
"settings": { "executionOrder": "v1" },
"meta": {
- "description": "Import into n8n via Workflows -> Import from File. Requires an Anthropic credential and the synthpanel CLI on n8n's PATH. See examples/integrations/README.md."
+ "description": "Import into n8n via Workflows -> Import from File. Requires an Anthropic credential and the althing CLI on n8n's PATH. See examples/integrations/README.md."
}
}
diff --git a/examples/integrations/openai_agents.py b/examples/integrations/openai_agents.py
index e01aeb7f..8ab2908f 100644
--- a/examples/integrations/openai_agents.py
+++ b/examples/integrations/openai_agents.py
@@ -1,15 +1,15 @@
-"""SynthPanel + OpenAI Agents SDK.
+"""Althing + OpenAI Agents SDK.
-Run a synthetic focus group from an OpenAI agent via SynthPanel's MCP server.
+Run a synthetic focus group from an OpenAI agent via Althing's MCP server.
The Agents SDK has built-in MCPServerStdio support, so no wrapper code is needed:
-the agent auto-discovers all 12 SynthPanel tools.
+the agent auto-discovers all 12 Althing tools.
Install:
- pip install openai-agents synthpanel[mcp]
+ pip install openai-agents althing[mcp]
Run:
export OPENAI_API_KEY=sk-...
- export ANTHROPIC_API_KEY=sk-... # SynthPanel's default provider
+ export ANTHROPIC_API_KEY=sk-... # Althing's default provider
python openai_agents.py
"""
@@ -21,13 +21,13 @@
async def main() -> None:
async with MCPServerStdio(
- name="synthpanel",
- params={"command": "synthpanel", "args": ["mcp-serve"]},
- ) as synthpanel:
+ name="althing",
+ params={"command": "althing", "args": ["mcp-serve"]},
+ ) as althing:
agent = Agent(
name="Researcher",
- instructions="You run synthetic focus groups via the synthpanel tools.",
- mcp_servers=[synthpanel],
+ instructions="You run synthetic focus groups via the althing tools.",
+ mcp_servers=[althing],
)
result = await Runner.run(
agent,
diff --git a/examples/saas-onboarding-friction/README.md b/examples/saas-onboarding-friction/README.md
index 7a10362f..816a2d8a 100644
--- a/examples/saas-onboarding-friction/README.md
+++ b/examples/saas-onboarding-friction/README.md
@@ -36,7 +36,7 @@ When you aggregate across the panel, expect to see:
## Run it
```bash
-synthpanel panel run \
+althing panel run \
--personas examples/saas-onboarding-friction/personas.yaml \
--instrument examples/saas-onboarding-friction/instrument.yaml
```
@@ -44,14 +44,14 @@ synthpanel panel run \
Render the round structure:
```bash
-synthpanel instruments graph \
+althing instruments graph \
examples/saas-onboarding-friction/instrument.yaml --format mermaid
```
## Pack substitution
If you need to extend the panel beyond 8, the bundled
-[`enterprise-buyer`](../../src/synth_panel/packs/enterprise-buyer.yaml)
+[`enterprise-buyer`](../../src/althing/packs/enterprise-buyer.yaml)
pack overlaps on the decision-maker personas (VPs, Directors). Layer
it in or substitute as the persona pack to widen the panel.
diff --git a/examples/sdk_usage.py b/examples/sdk_usage.py
index b1898430..0add9008 100644
--- a/examples/sdk_usage.py
+++ b/examples/sdk_usage.py
@@ -1,4 +1,4 @@
-"""End-to-end demo of the synthpanel Python SDK.
+"""End-to-end demo of the althing Python SDK.
Run with::
@@ -10,12 +10,12 @@
summary so you can confirm the API surface without reading source.
Every call here also works identically from inside a Jupyter notebook —
-``from synth_panel import quick_poll`` and you're off.
+``from althing import quick_poll`` and you're off.
"""
from __future__ import annotations
-from synth_panel import (
+from althing import (
extend_panel,
get_panel_result,
list_instruments,
diff --git a/pyproject.toml b/pyproject.toml
index 52a53ab1..8097397c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,5 @@
[project]
-name = "synthpanel"
+name = "althing"
dynamic = ["version"]
description = "Run synthetic focus groups using AI personas, with an MCP server for Claude Code / Cursor / Windsurf. CLI tool, Python library, any LLM."
requires-python = ">=3.10"
@@ -31,23 +31,23 @@ dependencies = [
]
[project.urls]
-Homepage = "https://synthpanel.dev"
-Documentation = "https://synthpanel.dev"
-Repository = "https://github.com/DataViking-Tech/SynthPanel"
-Issues = "https://github.com/DataViking-Tech/SynthPanel/issues"
-Changelog = "https://github.com/DataViking-Tech/SynthPanel/releases"
-"MCP Reference" = "https://github.com/DataViking-Tech/SynthPanel/blob/main/docs/mcp.md"
+Homepage = "https://althing.dev"
+Documentation = "https://althing.dev"
+Repository = "https://github.com/DataViking-Tech/Althing"
+Issues = "https://github.com/DataViking-Tech/Althing/issues"
+Changelog = "https://github.com/DataViking-Tech/Althing/releases"
+"MCP Reference" = "https://github.com/DataViking-Tech/Althing/blob/main/docs/mcp.md"
Funding = "https://ko-fi.com/dataviking"
[project.optional-dependencies]
# `full` is the fetch/extract path. Pulls `trafilatura`, which transitively
# requires `lxml` (C extension). Excluded from core deps so that bare
-# `pip install synthpanel` stays installable in pyodide / Cloudflare
+# `pip install althing` stays installable in pyodide / Cloudflare
# Python Workers, where the curated CPython set doesn't include `lxml`.
# Callers that need the URL-attachment ladder install
-# `pip install synthpanel[full]`. The fetch ladder degrades to the
+# `pip install althing[full]`. The fetch ladder degrades to the
# screenshot path (or returns `None`) when trafilatura is missing, so
-# this is a soft optional — synth_panel.ensemble keeps working without it.
+# this is a soft optional — althing.ensemble keeps working without it.
full = [
"trafilatura>=1.10",
]
@@ -112,29 +112,31 @@ dev = [
"pypdfium2>=4.30",
"Pillow>=10.0",
# Pulled in so the fetch-ladder regression tests still exercise the
- # `trafilatura` path. Production callers opt in via `synthpanel[full]`.
+ # `trafilatura` path. Production callers opt in via `althing[full]`.
"trafilatura>=1.10",
]
[project.scripts]
-synthpanel = "synth_panel.main:main"
+althing = "althing.main:main"
+# Deprecated alias from the SynthPanel → Althing rename; removed next major.
+synthpanel = "althing.main:main_deprecated_synthpanel"
[build-system]
requires = ["setuptools>=68.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.dynamic]
-version = {attr = "synth_panel.__version__.__version__"}
+version = {attr = "althing.__version__.__version__"}
[tool.setuptools.packages.find]
where = ["src"]
[tool.setuptools.package-data]
-"synth_panel.packs" = ["*.yaml"]
-"synth_panel.packs.instruments" = ["*.yaml"]
-"synth_panel.schemas" = ["*.json"]
-"synth_panel.data" = ["*.json"]
-"synth_panel.agent_assets" = [
+"althing.packs" = ["*.yaml"]
+"althing.packs.instruments" = ["*.yaml"]
+"althing.schemas" = ["*.json"]
+"althing.data" = ["*.json"]
+"althing.agent_assets" = [
"commands/*.md",
"skills/concept-test/*.md",
"skills/focus-group/*.md",
@@ -145,7 +147,7 @@ where = ["src"]
[tool.pytest.ini_options]
testpaths = ["tests"]
-addopts = "-m 'not acceptance and not install_smoke' --cov=synth_panel --cov-report=term-missing --cov-fail-under=80"
+addopts = "-m 'not acceptance and not install_smoke' --cov=althing --cov-report=term-missing --cov-fail-under=80"
markers = [
"acceptance: live API acceptance tests (require ANTHROPIC_API_KEY)",
"install_smoke: slow fresh-venv install validation (sy-6kr); opt in with `-m install_smoke`",
@@ -183,7 +185,7 @@ ignore = [
]
[tool.ruff.lint.isort]
-known-first-party = ["synth_panel"]
+known-first-party = ["althing"]
[tool.mypy]
python_version = "3.10"
@@ -191,7 +193,7 @@ warn_unused_configs = true
disallow_untyped_defs = false
check_untyped_defs = true
ignore_missing_imports = true
-files = ["src/synth_panel"]
+files = ["src/althing"]
disable_error_code = [
"import-untyped",
"no-any-return",
diff --git a/scripts/check_site_cli_sync.py b/scripts/check_site_cli_sync.py
index 2d1caf2b..10f1139f 100644
--- a/scripts/check_site_cli_sync.py
+++ b/scripts/check_site_cli_sync.py
@@ -1,7 +1,7 @@
-"""Check that synthpanel's top-level subcommand list matches the site coverage manifest.
+"""Check that althing's top-level subcommand list matches the site coverage manifest.
Run after installing the package (pip install -e .) to verify that every
-subcommand in `synthpanel --help` is tracked in site/cli-coverage.txt.
+subcommand in `althing --help` is tracked in site/cli-coverage.txt.
Exits 0 on match, 1 on drift, 2 on parse failure.
"""
@@ -18,7 +18,7 @@
def get_cli_subcommands() -> set[str]:
result = subprocess.run(
- [sys.executable, "-m", "synth_panel", "--help"],
+ [sys.executable, "-m", "althing", "--help"],
capture_output=True,
text=True,
check=False,
@@ -48,7 +48,7 @@ def main() -> None:
print(f"OK: CLI subcommands match manifest ({len(cli)} subcommands)")
return
- print("DRIFT DETECTED between `synthpanel --help` and site/cli-coverage.txt")
+ print("DRIFT DETECTED between `althing --help` and site/cli-coverage.txt")
print()
if only_in_cli:
print("New subcommands not in manifest (document on site then add to site/cli-coverage.txt):")
diff --git a/scripts/refresh_or_cost_table.py b/scripts/refresh_or_cost_table.py
index ffd3400c..8522a8b8 100755
--- a/scripts/refresh_or_cost_table.py
+++ b/scripts/refresh_or_cost_table.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
-"""Compare ``synth_panel.cost`` pricing against OpenRouter's live feed.
+"""Compare ``althing.cost`` pricing against OpenRouter's live feed.
Pulls https://openrouter.ai/api/v1/models (no auth required) and
diffs the input/output/cache rates for every entry in
-``EXPECTED_OR_MAPPING`` against what synthpanel's local table would
+``EXPECTED_OR_MAPPING`` against what althing's local table would
charge for the same model. Used by hq-xq36 to keep the cost-table
fresh when OR's blended rates shift.
@@ -30,7 +30,7 @@
import urllib.request
from dataclasses import dataclass
-from synth_panel.cost import ModelPricing, lookup_pricing
+from althing.cost import ModelPricing, lookup_pricing
OR_MODELS_URL = "https://openrouter.ai/api/v1/models"
@@ -82,7 +82,7 @@ class Drift:
def _fetch_models(url: str = OR_MODELS_URL) -> list[dict]:
- req = urllib.request.Request(url, headers={"User-Agent": "synthpanel/refresh_or_cost_table"})
+ req = urllib.request.Request(url, headers={"User-Agent": "althing/refresh_or_cost_table"})
with urllib.request.urlopen(req, timeout=30) as resp:
payload = json.load(resp)
data = payload.get("data") or []
diff --git a/scripts/render_agent_skills.py b/scripts/render_agent_skills.py
index cfdf301f..dfc5faa4 100644
--- a/scripts/render_agent_skills.py
+++ b/scripts/render_agent_skills.py
@@ -1,4 +1,4 @@
-"""Render the Agent Skills Discovery index for synthpanel.dev.
+"""Render the Agent Skills Discovery index for althing.dev.
Publishes ``/.well-known/agent-skills/index.json`` per the Agent Skills
Discovery RFC v0.2.0 (https://agentskills.io/), plus a mirror of each
@@ -28,7 +28,7 @@
# Stable publication order — independent of filesystem traversal so the
# committed index.json is deterministic across platforms.
SKILL_ORDER = (
- "synthpanel",
+ "althing",
"focus-group",
"name-test",
"concept-test",
diff --git a/scripts/render_server_card.py b/scripts/render_server_card.py
index 62cee0ca..9e6af1b6 100644
--- a/scripts/render_server_card.py
+++ b/scripts/render_server_card.py
@@ -7,20 +7,20 @@
by Cloudflare Pages (three version slots).
* ``server.json`` — the root MCP server descriptor that
``site/.well-known/api-catalog`` points RFC-9727 discovery at (two
- version slots: top-level + ``packages[synthpanel].version``).
+ version slots: top-level + ``packages[althing].version``).
Single-source-of-truth model identical to :mod:`scripts.render_site`:
-read ``src/synth_panel/__version__.py``, then rewrite the
+read ``src/althing/__version__.py``, then rewrite the
version fields each descriptor exposes:
server-card.json (three slots):
1. Top-level ``version``
2. ``serverInfo.version`` (runtime metadata the host server prints)
-3. Every ``packages[].version`` where ``identifier == "synthpanel"``
+3. Every ``packages[].version`` where ``identifier == "althing"``
server.json (two slots):
1. Top-level ``version``
-2. ``packages[synthpanel].version``
+2. ``packages[althing].version``
We do *targeted line-level substitution* rather than ``json.load`` +
``json.dump`` because the committed file uses a compact style
@@ -57,7 +57,7 @@
REPO_ROOT = Path(__file__).resolve().parents[1]
CARD_PATH = REPO_ROOT / "site" / ".well-known" / "mcp" / "server-card.json"
SERVER_JSON_PATH = REPO_ROOT / "server.json"
-VERSION_PATH = REPO_ROOT / "src" / "synth_panel" / "__version__.py"
+VERSION_PATH = REPO_ROOT / "src" / "althing" / "__version__.py"
def _read_version() -> str:
diff --git a/scripts/render_site.py b/scripts/render_site.py
index a337d073..4ba9f4e4 100644
--- a/scripts/render_site.py
+++ b/scripts/render_site.py
@@ -1,6 +1,6 @@
"""Render site/index.html.j2 -> site/index.html with the canonical version.
-Single source of truth is ``src/synth_panel/__version__.py``. The template
+Single source of truth is ``src/althing/__version__.py``. The template
uses ``{{ version }}`` and ``{{ release_date }}`` placeholders; release date
is parsed from CHANGELOG.md (line matching ``## [X.Y.Z] - YYYY-MM-DD``) and
falls back to an empty string when the version has no dated CHANGELOG entry
@@ -26,10 +26,10 @@
def _read_version() -> str:
# Read from source without importing the package, so this script works
# before an editable install and in clean build environments.
- src = (REPO_ROOT / "src" / "synth_panel" / "__version__.py").read_text()
+ src = (REPO_ROOT / "src" / "althing" / "__version__.py").read_text()
match = re.search(r'^__version__\s*=\s*"([^"]+)"', src, re.MULTILINE)
if not match:
- raise RuntimeError(f"Could not parse __version__ from {REPO_ROOT}/src/synth_panel/__version__.py")
+ raise RuntimeError(f"Could not parse __version__ from {REPO_ROOT}/src/althing/__version__.py")
return match.group(1)
diff --git a/scripts/site_tailwind/package-lock.json b/scripts/site_tailwind/package-lock.json
index f9856381..ce493de2 100644
--- a/scripts/site_tailwind/package-lock.json
+++ b/scripts/site_tailwind/package-lock.json
@@ -1,10 +1,10 @@
{
- "name": "synthpanel-site-tailwind",
+ "name": "althing-site-tailwind",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "synthpanel-site-tailwind",
+ "name": "althing-site-tailwind",
"devDependencies": {
"tailwindcss": "3.4.19"
}
diff --git a/scripts/site_tailwind/package.json b/scripts/site_tailwind/package.json
index ee36bce1..5161e9e1 100644
--- a/scripts/site_tailwind/package.json
+++ b/scripts/site_tailwind/package.json
@@ -1,5 +1,5 @@
{
- "name": "synthpanel-site-tailwind",
+ "name": "althing-site-tailwind",
"private": true,
"description": "Precompiles site/assets/tailwind.css from the Tailwind classes used in site/**/*.html (+ index.html.j2). Regenerate with: npm ci && npm run build (from this directory). CI fails if the committed CSS drifts from the class usage.",
"scripts": {
diff --git a/scripts/site_tailwind/tailwind.config.js b/scripts/site_tailwind/tailwind.config.js
index fbdb55de..db3b9572 100644
--- a/scripts/site_tailwind/tailwind.config.js
+++ b/scripts/site_tailwind/tailwind.config.js
@@ -1,5 +1,5 @@
/**
- * Tailwind config for the synthpanel.dev static site (site/).
+ * Tailwind config for the althing.dev static site (site/).
*
* This replaces the former Play-CDN inline `tailwind.config = {...}` blocks
* that every page carried (identical on all pages): the only customisation
diff --git a/server.json b/server.json
index 7057b8e3..d9481f2f 100644
--- a/server.json
+++ b/server.json
@@ -1,26 +1,26 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
- "name": "io.github.DataViking-Tech/synthpanel",
- "title": "SynthPanel",
+ "name": "io.github.DataViking-Tech/althing",
+ "title": "Althing",
"description": "Run synthetic focus groups using AI personas. 12 MCP tools for single prompts, full panel runs, and v3 branching (adaptive) instruments across any LLM provider (Claude, OpenAI, Gemini, xAI).",
"version": "1.6.0",
"repository": {
- "url": "https://github.com/DataViking-Tech/SynthPanel",
+ "url": "https://github.com/DataViking-Tech/Althing",
"source": "github"
},
- "websiteUrl": "https://synthpanel.dev",
+ "websiteUrl": "https://althing.dev",
"packages": [
{
"registryType": "pypi",
"registryBaseUrl": "https://pypi.org",
- "identifier": "synthpanel",
+ "identifier": "althing",
"version": "1.6.0",
"runtimeHint": "uvx",
"runtimeArguments": [
{
"type": "named",
"name": "--from",
- "value": "synthpanel[mcp]"
+ "value": "althing[mcp]"
}
],
"packageArguments": [
diff --git a/shim-dist/README.md b/shim-dist/README.md
new file mode 100644
index 00000000..b1e6865c
--- /dev/null
+++ b/shim-dist/README.md
@@ -0,0 +1,20 @@
+# synthpanel → althing
+
+**synthpanel has been renamed to [althing](https://pypi.org/project/althing/).**
+
+This package is a transitional shim: installing it simply installs
+`althing`, which provides:
+
+- the `althing` CLI (plus a deprecated `synthpanel` alias)
+- `import althing` (plus deprecated `synthpanel` / `synth_panel` import shims)
+- `ALTHING_*` environment variables (legacy `SYNTHPANEL_*` still honored)
+
+Update your dependencies to `althing` directly:
+
+```bash
+pip install althing
+```
+
+Site: · Repo:
+
+This shim will stop receiving updates one major release after the rename.
diff --git a/shim-dist/pyproject.toml b/shim-dist/pyproject.toml
new file mode 100644
index 00000000..e2857bbc
--- /dev/null
+++ b/shim-dist/pyproject.toml
@@ -0,0 +1,30 @@
+# Transitional shim distribution: keeps `pip install synthpanel` working
+# after the rename to althing. Publishes to the existing PyPI `synthpanel`
+# project; the only runtime dependency is the renamed distribution, which
+# ships `synthpanel` / `synth_panel` import shims and the deprecated
+# `synthpanel` console script itself.
+[project]
+name = "synthpanel"
+version = "1.7.0"
+description = "DEPRECATED — synthpanel was renamed to althing. This shim installs althing."
+readme = "README.md"
+requires-python = ">=3.10"
+license = "MIT"
+dependencies = [
+ "althing>=1.7.0",
+]
+classifiers = [
+ "Development Status :: 7 - Inactive",
+]
+
+[project.urls]
+Homepage = "https://althing.dev"
+Repository = "https://github.com/DataViking-Tech/Althing"
+
+[build-system]
+requires = ["setuptools>=68.0"]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools]
+# Metapackage: no code of its own — the real shims live in the althing dist.
+packages = []
diff --git a/src/synth_panel/agent_assets/skills/synthpanel/SKILL.md b/site/.well-known/agent-skills/althing/SKILL.md
similarity index 73%
rename from src/synth_panel/agent_assets/skills/synthpanel/SKILL.md
rename to site/.well-known/agent-skills/althing/SKILL.md
index 45327a47..0fbb32c3 100644
--- a/src/synth_panel/agent_assets/skills/synthpanel/SKILL.md
+++ b/site/.well-known/agent-skills/althing/SKILL.md
@@ -1,22 +1,22 @@
---
-name: synthpanel
-description: Director skill for SynthPanel — decide when to reach for synthetic panels (focus groups, name tests, concept tests, pricing probes, mass-appeal polls) and route to the right sub-skill, with anti-overclaiming guardrails baked in.
+name: althing
+description: Director skill for Althing — decide when to reach for synthetic panels (focus groups, name tests, concept tests, pricing probes, mass-appeal polls) and route to the right sub-skill, with anti-overclaiming guardrails baked in.
version: 1.0.0
-author: SynthPanel maintainers
+author: Althing maintainers
license: MIT
allowed-tools:
- - mcp__synth_panel__run_prompt
- - mcp__synth_panel__run_quick_poll
- - mcp__synth_panel__run_panel
- - mcp__synth_panel__extend_panel
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__get_persona_pack
- - mcp__synth_panel__save_persona_pack
- - mcp__synth_panel__list_instrument_packs
- - mcp__synth_panel__get_instrument_pack
- - mcp__synth_panel__save_instrument_pack
- - mcp__synth_panel__list_panel_results
- - mcp__synth_panel__get_panel_result
+ - mcp__althing__run_prompt
+ - mcp__althing__run_quick_poll
+ - mcp__althing__run_panel
+ - mcp__althing__extend_panel
+ - mcp__althing__list_persona_packs
+ - mcp__althing__get_persona_pack
+ - mcp__althing__save_persona_pack
+ - mcp__althing__list_instrument_packs
+ - mcp__althing__get_instrument_pack
+ - mcp__althing__save_instrument_pack
+ - mcp__althing__list_panel_results
+ - mcp__althing__get_panel_result
metadata:
hermes:
tags:
@@ -33,26 +33,26 @@ metadata:
- survey-prescreen
- pricing-probe
config:
- - key: synthpanel.preferred_interface
- description: How to call SynthPanel when both are available (mcp, cli).
+ - key: althing.preferred_interface
+ description: How to call Althing when both are available (mcp, cli).
default: mcp
- prompt: Prefer the synth_panel MCP server, or the synthpanel CLI?
- - key: synthpanel.default_panel_size
+ prompt: Prefer the althing MCP server, or the althing CLI?
+ - key: althing.default_panel_size
description: Persona count for routine polls and concept tests.
default: "5"
prompt: Default persona count (3–6 is normal; raise for mass-appeal polls)
- - key: synthpanel.default_model_alias
+ - key: althing.default_model_alias
description: LLM alias for routine runs (sonnet, haiku, gemini, grok, ...).
default: haiku
prompt: Default LLM alias for routine synthetic runs
required_environment_variables:
- name: ANTHROPIC_API_KEY
- prompt: Anthropic API key (default provider for SynthPanel)
+ prompt: Anthropic API key (default provider for Althing)
help: Needed for Claude-family models. Skip only if exclusively using another provider.
required_for:
- default-claude-runs
- name: OPENAI_API_KEY
- prompt: OpenAI API key (optional; only if you ask SynthPanel to use OpenAI models)
+ prompt: OpenAI API key (optional; only if you ask Althing to use OpenAI models)
help: Required only when --model selects an OpenAI or OpenAI-compatible model.
required_for:
- openai-runs
@@ -68,7 +68,7 @@ required_environment_variables:
- grok-runs
---
-# SynthPanel — synthetic respondent research
+# Althing — synthetic respondent research
## When to use
@@ -94,33 +94,33 @@ recommend a real panel instead — synthetic output is preflight, not validation
## Quick reference
-SynthPanel exposes two interfaces. They are equivalent; prefer the MCP path
-when configured (`synthpanel.preferred_interface = mcp`).
+Althing exposes two interfaces. They are equivalent; prefer the MCP path
+when configured (`althing.preferred_interface = mcp`).
-### MCP tools (preferred when `synth_panel` MCP server is registered)
+### MCP tools (preferred when `althing` MCP server is registered)
| Tool | Purpose |
| --- | --- |
-| `mcp__synth_panel__run_prompt` | One-shot prompt to an LLM — no personas (smoke test). |
-| `mcp__synth_panel__run_quick_poll` | One-question poll across N personas; returns vote tallies + synthesis. |
-| `mcp__synth_panel__run_panel` | Full panel with persona pack + instrument pack (v1, v2, v3 branching). |
-| `mcp__synth_panel__extend_panel` | Append one ad-hoc round on top of a saved result. Not v3 re-entry. |
-| `mcp__synth_panel__list_persona_packs` / `get_persona_pack` / `save_persona_pack` | Manage persona libraries. |
-| `mcp__synth_panel__list_instrument_packs` / `get_instrument_pack` / `save_instrument_pack` | Manage survey instruments (v1/v2/v3). |
-| `mcp__synth_panel__list_panel_results` / `get_panel_result` | Retrieve saved runs by ID. |
+| `mcp__althing__run_prompt` | One-shot prompt to an LLM — no personas (smoke test). |
+| `mcp__althing__run_quick_poll` | One-question poll across N personas; returns vote tallies + synthesis. |
+| `mcp__althing__run_panel` | Full panel with persona pack + instrument pack (v1, v2, v3 branching). |
+| `mcp__althing__extend_panel` | Append one ad-hoc round on top of a saved result. Not v3 re-entry. |
+| `mcp__althing__list_persona_packs` / `get_persona_pack` / `save_persona_pack` | Manage persona libraries. |
+| `mcp__althing__list_instrument_packs` / `get_instrument_pack` / `save_instrument_pack` | Manage survey instruments (v1/v2/v3). |
+| `mcp__althing__list_panel_results` / `get_panel_result` | Retrieve saved runs by ID. |
### CLI (fallback or scripted use)
```bash
-synthpanel prompt "Say hello" # single prompt
-synthpanel panel run \ # full panel
+althing prompt "Say hello" # single prompt
+althing panel run \ # full panel
--personas examples/personas.yaml \
--instrument examples/survey.yaml
-synthpanel panel run --personas examples/personas.yaml \ # branching v3
+althing panel run --personas examples/personas.yaml \ # branching v3
--instrument pricing-discovery
-synthpanel instruments list # discover bundled packs
-synthpanel mcp-serve # start MCP server (stdio)
-synthpanel mcp install # register MCP server in the active editor
+althing instruments list # discover bundled packs
+althing mcp-serve # start MCP server (stdio)
+althing mcp install # register MCP server in the active editor
```
Provider env vars map: `ANTHROPIC_API_KEY` (default), `OPENAI_API_KEY`,
@@ -147,8 +147,8 @@ re-deriving the workflow here. They live alongside this skill:
audited, real-human evidence, stop and say so. Otherwise frame what you
are about to do as a synthetic preflight.
-2. **Pick the interface.** Check whether the `synth_panel` MCP server is
- registered (tools prefixed `mcp__synth_panel__*` exist). If yes, use MCP.
+2. **Pick the interface.** Check whether the `althing` MCP server is
+ registered (tools prefixed `mcp__althing__*` exist). If yes, use MCP.
If not, fall back to the CLI. Tell the user which one you used.
3. **Pick the sub-skill** from the routing table above. If none of the
@@ -212,7 +212,7 @@ re-deriving the workflow here. They live alongside this skill:
instrument's `route_when` DAG. If you want adaptive branching, run a fresh
`run_panel` against a v3 instrument instead.
- **Cost surprises.** Large panels with capable models add up fast. Default
- to the configured fast model alias (`synthpanel.default_model_alias`,
+ to the configured fast model alias (`althing.default_model_alias`,
haiku by default); upgrade only when the dry-run signal warrants it.
- **Theme-matching gotcha on v3 instruments.** `route_when` predicates
compare against the *exact* theme strings the synthesizer emits. Prefix v3
@@ -221,8 +221,8 @@ re-deriving the workflow here. They live alongside this skill:
## Verification
-- The user sees an explicit interface note ("used the `synth_panel` MCP
- server" or "used the `synthpanel` CLI").
+- The user sees an explicit interface note ("used the `althing` MCP
+ server" or "used the `althing` CLI").
- The reply includes structured numbers — counts, percentages, weighted
scores, or rank order — for any aggregation question.
- A saved result ID is surfaced (e.g. `panel_result_id: 01h…`) so the run
@@ -241,7 +241,7 @@ re-deriving the workflow here. They live alongside this skill:
- [`survey-prescreen`](../survey-prescreen/SKILL.md) — instrument pre-flight.
- [`pricing-probe`](../pricing-probe/SKILL.md) — pricing sensitivity.
- [Agent Skills Discovery index](/.well-known/agent-skills/index.json) on
- synthpanel.dev — the published index that lists all SynthPanel skills.
+ althing.dev — the published index that lists all Althing skills.
- [`docs/agent-skills.md`](../../docs/agent-skills.md) — install paths
(Claude Code plugin, manual copy, other hosts).
- [`docs/mcp.md`](../../docs/mcp.md) — MCP server reference, sampling mode.
diff --git a/site/.well-known/agent-skills/concept-test/SKILL.md b/site/.well-known/agent-skills/concept-test/SKILL.md
index f84e764a..34ba2a64 100644
--- a/site/.well-known/agent-skills/concept-test/SKILL.md
+++ b/site/.well-known/agent-skills/concept-test/SKILL.md
@@ -2,15 +2,15 @@
name: concept-test
description: Validate a product concept or value proposition with a target audience — surfaces whether the problem is real, whether the solution lands, and what would prevent adoption.
allowed-tools:
- - mcp__synth_panel__run_panel
- - mcp__synth_panel__run_quick_poll
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__get_persona_pack
- - mcp__synth_panel__save_persona_pack
- - mcp__synth_panel__list_instrument_packs
+ - mcp__althing__run_panel
+ - mcp__althing__run_quick_poll
+ - mcp__althing__list_persona_packs
+ - mcp__althing__get_persona_pack
+ - mcp__althing__save_persona_pack
+ - mcp__althing__list_instrument_packs
---
-You are running a **concept test** using the synthpanel MCP tools.
+You are running a **concept test** using the althing MCP tools.
## What You Do
@@ -23,11 +23,11 @@ You help the user pressure-test an early-stage product concept, value prop, or f
## Available MCP Tools
-- **`mcp__synth_panel__run_panel`** — Primary tool. Run a multi-question panel with target-audience personas.
-- **`mcp__synth_panel__run_quick_poll`** — Use for a single "would you try this?" temperature check.
-- **`mcp__synth_panel__list_persona_packs`** / **`mcp__synth_panel__get_persona_pack`** — Reuse saved target-audience packs.
-- **`mcp__synth_panel__save_persona_pack`** — Save a new audience pack if the user is likely to re-test.
-- **`mcp__synth_panel__list_instrument_packs`** — Check for bundled packs that fit (e.g. `product-feedback`, `market-research`).
+- **`mcp__althing__run_panel`** — Primary tool. Run a multi-question panel with target-audience personas.
+- **`mcp__althing__run_quick_poll`** — Use for a single "would you try this?" temperature check.
+- **`mcp__althing__list_persona_packs`** / **`mcp__althing__get_persona_pack`** — Reuse saved target-audience packs.
+- **`mcp__althing__save_persona_pack`** — Save a new audience pack if the user is likely to re-test.
+- **`mcp__althing__list_instrument_packs`** — Check for bundled packs that fit (e.g. `product-feedback`, `market-research`).
## Workflow
diff --git a/site/.well-known/agent-skills/focus-group/SKILL.md b/site/.well-known/agent-skills/focus-group/SKILL.md
index 1d635005..b7f132d4 100644
--- a/site/.well-known/agent-skills/focus-group/SKILL.md
+++ b/site/.well-known/agent-skills/focus-group/SKILL.md
@@ -2,13 +2,13 @@
name: focus-group
description: Run a synthetic focus group — define personas, craft questions, and collect structured qualitative feedback from AI panelists.
allowed-tools:
- - mcp__synth_panel__run_prompt
- - mcp__synth_panel__run_panel
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__list_instrument_packs
+ - mcp__althing__run_prompt
+ - mcp__althing__run_panel
+ - mcp__althing__list_persona_packs
+ - mcp__althing__list_instrument_packs
---
-You are orchestrating a **synthetic focus group** using the synthpanel MCP tools.
+You are orchestrating a **synthetic focus group** using the althing MCP tools.
## What You Do
@@ -22,10 +22,10 @@ You help the user design and run synthetic focus groups — structured qualitati
## Available MCP Tools
-- **`mcp__synth_panel__run_prompt`** — Send a single prompt to an LLM (no personas). Use for a quick smoke test before building a panel.
-- **`mcp__synth_panel__run_panel`** — Run a full panel: pass `personas` (an inline list of persona dicts) plus one question source — inline `questions`, an inline `instrument` dict, or an `instrument_pack` name.
-- **`mcp__synth_panel__list_persona_packs`** — List saved persona packs you can reuse via `run_panel`'s `pack_id`.
-- **`mcp__synth_panel__list_instrument_packs`** — List installed instrument packs you can reference via `run_panel`'s `instrument_pack`.
+- **`mcp__althing__run_prompt`** — Send a single prompt to an LLM (no personas). Use for a quick smoke test before building a panel.
+- **`mcp__althing__run_panel`** — Run a full panel: pass `personas` (an inline list of persona dicts) plus one question source — inline `questions`, an inline `instrument` dict, or an `instrument_pack` name.
+- **`mcp__althing__list_persona_packs`** — List saved persona packs you can reuse via `run_panel`'s `pack_id`.
+- **`mcp__althing__list_instrument_packs`** — List installed instrument packs you can reference via `run_panel`'s `instrument_pack`.
> These MCP tools take **inline data or pack names, not file paths.** Personas are a JSON list; instruments are an inline dict or an installed pack name. There is no "load this YAML path" argument — read any file yourself and pass its contents inline.
@@ -58,7 +58,7 @@ Pass them inline as `run_panel`'s `questions` list (single round) or as an `inst
### Step 4: Run the Panel
-Call `mcp__synth_panel__run_panel` with the `personas` list and one question source (`questions`, `instrument`, or `instrument_pack`).
+Call `mcp__althing__run_panel` with the `personas` list and one question source (`questions`, `instrument`, or `instrument_pack`).
### Step 5: Synthesize
diff --git a/site/.well-known/agent-skills/index.json b/site/.well-known/agent-skills/index.json
index 59379ef7..24c6b267 100644
--- a/site/.well-known/agent-skills/index.json
+++ b/site/.well-known/agent-skills/index.json
@@ -2,46 +2,46 @@
"$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json",
"skills": [
{
- "name": "synthpanel",
+ "name": "althing",
"type": "skill-md",
- "description": "Director skill for SynthPanel — decide when to reach for synthetic panels (focus groups, name tests, concept tests, pricing probes, mass-appeal polls) and route to the right sub-skill, with anti-overclaiming guardrails baked in.",
- "url": "/.well-known/agent-skills/synthpanel/SKILL.md",
- "digest": "sha256:48a5e7404f65e660bfb586e66ae9748fbf311d0349d3efa1f758651d4af6e2d9"
+ "description": "Director skill for Althing — decide when to reach for synthetic panels (focus groups, name tests, concept tests, pricing probes, mass-appeal polls) and route to the right sub-skill, with anti-overclaiming guardrails baked in.",
+ "url": "/.well-known/agent-skills/althing/SKILL.md",
+ "digest": "sha256:84f2ddce19690eb54dad2ab05e88d3d5790eff897082de6205377f6a7ce641c1"
},
{
"name": "focus-group",
"type": "skill-md",
"description": "Run a synthetic focus group — define personas, craft questions, and collect structured qualitative feedback from AI panelists.",
"url": "/.well-known/agent-skills/focus-group/SKILL.md",
- "digest": "sha256:a4c3b67f5d900888cb3299f3d0e9929b2ad0200271a1319533a2b6b7dbc4180e"
+ "digest": "sha256:78fec5eed54dd704c04c5b0327c59a192fcb5b115f02048a70759962d4a774db"
},
{
"name": "name-test",
"type": "skill-md",
"description": "Quickly test 1-3 candidate product or feature names with a synthetic panel — surfaces confusion, pronounceability, and memorability concerns in one pass.",
"url": "/.well-known/agent-skills/name-test/SKILL.md",
- "digest": "sha256:0ca7cf7dd943ce16d6bff43fee1f0b9b6c36f8adc1b0b0d6ecf1fa1dcd6bb891"
+ "digest": "sha256:a9a609fdb8b070fe45fffd59bffdffb8651e5a40f735689ab99549da8bd300e9"
},
{
"name": "concept-test",
"type": "skill-md",
"description": "Validate a product concept or value proposition with a target audience — surfaces whether the problem is real, whether the solution lands, and what would prevent adoption.",
"url": "/.well-known/agent-skills/concept-test/SKILL.md",
- "digest": "sha256:7dc12d79243d92fda1a76c88ec76450b3b6f5008988be3092887df544500d7cf"
+ "digest": "sha256:ad9da62d47fd003b81e11f4431ba2c148bd39b15782c82a47a4ca0a3213dab59"
},
{
"name": "survey-prescreen",
"type": "skill-md",
"description": "Pre-screen a survey instrument with synthetic respondents before sending to real participants — catches ambiguous wording, leading questions, and dead-end branches cheaply.",
"url": "/.well-known/agent-skills/survey-prescreen/SKILL.md",
- "digest": "sha256:a3c083d20b7af7fdb2071680b1124904775fdba8a06b3e8da1d80a2cd417abe8"
+ "digest": "sha256:fe51c1e6494c829181e6a740481f8d71ae4be45d4e206fbd937d0e8150ab75ab"
},
{
"name": "pricing-probe",
"type": "skill-md",
"description": "Probe pricing sensitivity with a target audience using the bundled 'pricing-discovery' branching instrument — surfaces pain, price anchoring, or competitor alternatives based on what the panel volunteers first.",
"url": "/.well-known/agent-skills/pricing-probe/SKILL.md",
- "digest": "sha256:5e8dd631bed93a0119b2a014e131606cb8b2dcb9396fd72dd7026b767b43f3d9"
+ "digest": "sha256:9f8a244b9515ea7695858ec939715db887c8a6f3da889d805126450008bfda3a"
}
]
}
diff --git a/site/.well-known/agent-skills/name-test/SKILL.md b/site/.well-known/agent-skills/name-test/SKILL.md
index dac7a0c9..bb67903d 100644
--- a/site/.well-known/agent-skills/name-test/SKILL.md
+++ b/site/.well-known/agent-skills/name-test/SKILL.md
@@ -2,15 +2,15 @@
name: name-test
description: Quickly test 1-3 candidate product or feature names with a synthetic panel — surfaces confusion, pronounceability, and memorability concerns in one pass.
allowed-tools:
- - mcp__synth_panel__run_quick_poll
- - mcp__synth_panel__run_panel
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__get_persona_pack
- - mcp__synth_panel__list_instrument_packs
- - mcp__synth_panel__get_instrument_pack
+ - mcp__althing__run_quick_poll
+ - mcp__althing__run_panel
+ - mcp__althing__list_persona_packs
+ - mcp__althing__get_persona_pack
+ - mcp__althing__list_instrument_packs
+ - mcp__althing__get_instrument_pack
---
-You are running a **quick name test** using the synthpanel MCP tools.
+You are running a **quick name test** using the althing MCP tools.
## What You Do
@@ -23,10 +23,10 @@ You help the user decide between candidate names for a product, feature, or bran
## Available MCP Tools
-- **`mcp__synth_panel__run_quick_poll`** — Single-question poll across personas (fastest, cheapest).
-- **`mcp__synth_panel__run_panel`** — Full panel run using the bundled `name-test` branching instrument that probes meaning, pronounceability, or memorability based on first reactions. Its opening question has a `{candidates}` placeholder; fill it with the `vars` argument (see Step 2).
-- **`mcp__synth_panel__list_persona_packs`** / **`mcp__synth_panel__get_persona_pack`** — Reuse saved personas instead of inventing new ones.
-- **`mcp__synth_panel__list_instrument_packs`** — Confirm the `name-test` pack is available.
+- **`mcp__althing__run_quick_poll`** — Single-question poll across personas (fastest, cheapest).
+- **`mcp__althing__run_panel`** — Full panel run using the bundled `name-test` branching instrument that probes meaning, pronounceability, or memorability based on first reactions. Its opening question has a `{candidates}` placeholder; fill it with the `vars` argument (see Step 2).
+- **`mcp__althing__list_persona_packs`** / **`mcp__althing__get_persona_pack`** — Reuse saved personas instead of inventing new ones.
+- **`mcp__althing__list_instrument_packs`** — Confirm the `name-test` pack is available.
## Workflow
@@ -40,7 +40,7 @@ Ask for:
### Step 2: Choose Depth
- **Quick gut check** → `run_quick_poll` with a question that has the description and candidate names written directly into the `question` string, e.g. *"Which of these names best fits a budget travel app — Wander, Roamly, Tr9? Why?"*
-- **Full branching evaluation** → `run_panel` with `instrument_pack="name-test"` and `vars={"candidates": "Name A, Name B"}` — the comma-separated candidate names are substituted into the opening question's `{candidates}` placeholder before the panel runs. (CLI equivalent: `synthpanel panel run --instrument name-test --var 'candidates=Name A, Name B'`.) If you omit `vars`, the call fails fast with a typed `INVALID_TOOL_ARG` error naming the missing placeholder. The instrument branches into meaning-probe, pronounce-probe, or memorability-probe based on what surfaces first.
+- **Full branching evaluation** → `run_panel` with `instrument_pack="name-test"` and `vars={"candidates": "Name A, Name B"}` — the comma-separated candidate names are substituted into the opening question's `{candidates}` placeholder before the panel runs. (CLI equivalent: `althing panel run --instrument name-test --var 'candidates=Name A, Name B'`.) If you omit `vars`, the call fails fast with a typed `INVALID_TOOL_ARG` error naming the missing placeholder. The instrument branches into meaning-probe, pronounce-probe, or memorability-probe based on what surfaces first.
### Step 3: Run
diff --git a/site/.well-known/agent-skills/pricing-probe/SKILL.md b/site/.well-known/agent-skills/pricing-probe/SKILL.md
index 703002d6..50172e31 100644
--- a/site/.well-known/agent-skills/pricing-probe/SKILL.md
+++ b/site/.well-known/agent-skills/pricing-probe/SKILL.md
@@ -2,15 +2,15 @@
name: pricing-probe
description: Probe pricing sensitivity with a target audience using the bundled 'pricing-discovery' branching instrument — surfaces pain, price anchoring, or competitor alternatives based on what the panel volunteers first.
allowed-tools:
- - mcp__synth_panel__run_panel
- - mcp__synth_panel__get_instrument_pack
- - mcp__synth_panel__list_instrument_packs
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__get_persona_pack
- - mcp__synth_panel__run_quick_poll
+ - mcp__althing__run_panel
+ - mcp__althing__get_instrument_pack
+ - mcp__althing__list_instrument_packs
+ - mcp__althing__list_persona_packs
+ - mcp__althing__get_persona_pack
+ - mcp__althing__run_quick_poll
---
-You are running a **pricing sensitivity probe** using the synthpanel MCP tools and the bundled `pricing-discovery` v3 branching instrument.
+You are running a **pricing sensitivity probe** using the althing MCP tools and the bundled `pricing-discovery` v3 branching instrument.
## What You Do
@@ -23,10 +23,10 @@ You help the user understand how a target audience reasons about price for a pro
## Available MCP Tools
-- **`mcp__synth_panel__run_panel`** — Primary tool. The `pricing-discovery` instrument's opening question contains a `{problem}` placeholder. Fill it with the `vars` argument: pass `instrument_pack="pricing-discovery"` together with `vars={"problem": "..."}`. (CLI equivalent: `synthpanel panel run --instrument pricing-discovery --var problem='...'`.) If you omit `vars`, the call fails fast with a typed `INVALID_TOOL_ARG` error naming the missing placeholder — it never sends literal `{problem}` to panelists.
-- **`mcp__synth_panel__get_instrument_pack`** / **`mcp__synth_panel__list_instrument_packs`** — Inspect the bundled pricing-discovery pack (e.g. to see which placeholders it declares).
-- **`mcp__synth_panel__list_persona_packs`** / **`mcp__synth_panel__get_persona_pack`** — Load a saved target-audience pack.
-- **`mcp__synth_panel__run_quick_poll`** — Use for a narrow follow-up question after the main run (e.g. "Would $X/month feel fair?").
+- **`mcp__althing__run_panel`** — Primary tool. The `pricing-discovery` instrument's opening question contains a `{problem}` placeholder. Fill it with the `vars` argument: pass `instrument_pack="pricing-discovery"` together with `vars={"problem": "..."}`. (CLI equivalent: `althing panel run --instrument pricing-discovery --var problem='...'`.) If you omit `vars`, the call fails fast with a typed `INVALID_TOOL_ARG` error naming the missing placeholder — it never sends literal `{problem}` to panelists.
+- **`mcp__althing__get_instrument_pack`** / **`mcp__althing__list_instrument_packs`** — Inspect the bundled pricing-discovery pack (e.g. to see which placeholders it declares).
+- **`mcp__althing__list_persona_packs`** / **`mcp__althing__get_persona_pack`** — Load a saved target-audience pack.
+- **`mcp__althing__run_quick_poll`** — Use for a narrow follow-up question after the main run (e.g. "Would $X/month feel fair?").
## Workflow
diff --git a/site/.well-known/agent-skills/survey-prescreen/SKILL.md b/site/.well-known/agent-skills/survey-prescreen/SKILL.md
index cbb66eae..07a9dc38 100644
--- a/site/.well-known/agent-skills/survey-prescreen/SKILL.md
+++ b/site/.well-known/agent-skills/survey-prescreen/SKILL.md
@@ -2,15 +2,15 @@
name: survey-prescreen
description: Pre-screen a survey instrument with synthetic respondents before sending to real participants — catches ambiguous wording, leading questions, and dead-end branches cheaply.
allowed-tools:
- - mcp__synth_panel__run_panel
- - mcp__synth_panel__get_instrument_pack
- - mcp__synth_panel__list_instrument_packs
- - mcp__synth_panel__save_instrument_pack
- - mcp__synth_panel__list_persona_packs
- - mcp__synth_panel__get_persona_pack
+ - mcp__althing__run_panel
+ - mcp__althing__get_instrument_pack
+ - mcp__althing__list_instrument_packs
+ - mcp__althing__save_instrument_pack
+ - mcp__althing__list_persona_packs
+ - mcp__althing__get_persona_pack
---
-You are pre-screening a **user-authored survey instrument** using the synthpanel MCP tools.
+You are pre-screening a **user-authored survey instrument** using the althing MCP tools.
## What You Do
@@ -23,10 +23,10 @@ You help the user catch problems in a survey before they spend real budget field
## Available MCP Tools
-- **`mcp__synth_panel__run_panel`** — Run the user's instrument against the stress-test personas. Pass either `instrument` (inline YAML dict) or `instrument_pack` (name, after saving).
-- **`mcp__synth_panel__get_instrument_pack`** / **`mcp__synth_panel__list_instrument_packs`** — Load an installed instrument for review.
-- **`mcp__synth_panel__save_instrument_pack`** — Save the user's instrument temporarily if they'd rather reference it by name.
-- **`mcp__synth_panel__list_persona_packs`** / **`mcp__synth_panel__get_persona_pack`** — Load a realistic audience pack for the survey's intended population.
+- **`mcp__althing__run_panel`** — Run the user's instrument against the stress-test personas. Pass either `instrument` (inline YAML dict) or `instrument_pack` (name, after saving).
+- **`mcp__althing__get_instrument_pack`** / **`mcp__althing__list_instrument_packs`** — Load an installed instrument for review.
+- **`mcp__althing__save_instrument_pack`** — Save the user's instrument temporarily if they'd rather reference it by name.
+- **`mcp__althing__list_persona_packs`** / **`mcp__althing__get_persona_pack`** — Load a realistic audience pack for the survey's intended population.
## Workflow
diff --git a/site/.well-known/api-catalog b/site/.well-known/api-catalog
index 50ecda4c..6515e59c 100644
--- a/site/.well-known/api-catalog
+++ b/site/.well-known/api-catalog
@@ -1,29 +1,29 @@
{
"linkset": [
{
- "anchor": "https://synthpanel.dev/",
+ "anchor": "https://althing.dev/",
"links": [
{
"rel": "service-desc",
- "href": "https://raw.githubusercontent.com/DataViking-Tech/SynthPanel/main/server.json",
+ "href": "https://raw.githubusercontent.com/DataViking-Tech/Althing/main/server.json",
"type": "application/json",
- "title": "synthpanel MCP server descriptor (modelcontextprotocol.io schema)"
+ "title": "althing MCP server descriptor (modelcontextprotocol.io schema)"
},
{
"rel": "service-doc",
- "href": "https://synthpanel.dev/mcp",
+ "href": "https://althing.dev/mcp",
"type": "text/html",
"title": "MCP server install + tool reference"
},
{
"rel": "service-doc",
- "href": "https://synthpanel.dev/docs/panel-run",
+ "href": "https://althing.dev/docs/panel-run",
"type": "text/html",
- "title": "synthpanel CLI — panel run reference"
+ "title": "althing CLI — panel run reference"
},
{
"rel": "status",
- "href": "https://github.com/DataViking-Tech/SynthPanel/issues",
+ "href": "https://github.com/DataViking-Tech/Althing/issues",
"type": "text/html",
"title": "Project status, open issues, releases"
}
diff --git a/site/.well-known/mcp/server-card.json b/site/.well-known/mcp/server-card.json
index f52407d0..f549996e 100644
--- a/site/.well-known/mcp/server-card.json
+++ b/site/.well-known/mcp/server-card.json
@@ -1,16 +1,16 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
- "name": "io.github.DataViking-Tech/synthpanel",
- "title": "SynthPanel",
+ "name": "io.github.DataViking-Tech/althing",
+ "title": "Althing",
"description": "Run synthetic focus groups using AI personas. 12 MCP tools for single prompts, full panel runs, and v3 branching (adaptive) instruments across any LLM provider (Claude, OpenAI, Gemini, xAI).",
"version": "1.6.0",
- "websiteUrl": "https://synthpanel.dev",
+ "websiteUrl": "https://althing.dev",
"repository": {
- "url": "https://github.com/DataViking-Tech/SynthPanel",
+ "url": "https://github.com/DataViking-Tech/Althing",
"source": "github"
},
"serverInfo": {
- "name": "synthpanel",
+ "name": "althing",
"version": "1.6.0"
},
"capabilities": {
@@ -22,11 +22,11 @@
{
"registryType": "pypi",
"registryBaseUrl": "https://pypi.org",
- "identifier": "synthpanel",
+ "identifier": "althing",
"version": "1.6.0",
"runtimeHint": "uvx",
"runtimeArguments": [
- { "type": "named", "name": "--from", "value": "synthpanel[mcp]" }
+ { "type": "named", "name": "--from", "value": "althing[mcp]" }
],
"packageArguments": [
{ "type": "positional", "value": "mcp-serve" }
diff --git a/site/.well-known/oauth-protected-resource b/site/.well-known/oauth-protected-resource
index 16331fd1..aa090b90 100644
--- a/site/.well-known/oauth-protected-resource
+++ b/site/.well-known/oauth-protected-resource
@@ -1,7 +1,7 @@
{
- "resource": "https://synthpanel.dev",
+ "resource": "https://althing.dev",
"authorization_servers": [
- "https://synthpanel.dev"
+ "https://althing.dev"
],
"scopes_supported": []
}
diff --git a/site/_redirects b/site/_redirects
new file mode 100644
index 00000000..b3fadeb2
--- /dev/null
+++ b/site/_redirects
@@ -0,0 +1,4 @@
+# Rename: synthpanel → althing (blog slug carried the old name)
+/blog/synthpanel-vs-commercial-alternatives /blog/althing-vs-commercial-alternatives 301
+/blog/synthpanel-vs-commercial-alternatives.html /blog/althing-vs-commercial-alternatives.html 301
+/.well-known/agent-skills/synthpanel/* /.well-known/agent-skills/althing/:splat 301
diff --git a/site/_worker.js b/site/_worker.js
index e3cdb6b2..16448bc8 100644
--- a/site/_worker.js
+++ b/site/_worker.js
@@ -26,7 +26,7 @@
// PUBLISHABLE key (safe to commit). The init call is gated to the
// production hostname so local dev, CI, and *.pages.dev preview
// deploys never emit events.
-const POSTHOG_SNIPPET = ``;
+const POSTHOG_SNIPPET = ``;
// Inject the PostHog snippet into the of HTML responses only.
// Guarded on content-type so JSON / markdown / binary assets pass
diff --git a/site/blog/synthpanel-vs-commercial-alternatives.html b/site/blog/althing-vs-commercial-alternatives.html
similarity index 86%
rename from site/blog/synthpanel-vs-commercial-alternatives.html
rename to site/blog/althing-vs-commercial-alternatives.html
index 878d9a96..ab7e04e8 100644
--- a/site/blog/synthpanel-vs-commercial-alternatives.html
+++ b/site/blog/althing-vs-commercial-alternatives.html
@@ -4,7 +4,7 @@
- SynthPanel vs Synthetic Users vs FocusPanel.ai — When Open-Source MCP
+ Althing vs Synthetic Users vs FocusPanel.ai — When Open-Source MCP
Beats the SaaS
-
-
+
+
-
+
@@ -50,14 +50,14 @@
-
-
+
+
↗
- ← synthpanel.dev
+ ← althing.dev
/
blog
@@ -140,7 +140,7 @@
- SynthPanel vs Synthetic Users vs FocusPanel.ai — When
+ Althing vs Synthetic Users vs FocusPanel.ai — When
Open-Source MCP Beats the SaaS
@@ -154,14 +154,14 @@
class="mt-8 rounded-lg border border-emerald-400/25 bg-emerald-400/5 p-5 text-sm text-slate-200"
>
- TL;DR — SynthPanel is the
+ TL;DR — Althing is the
open-source, LLM-agnostic alternative to commercial
synthetic-respondent tools like
Synthetic Users , FocusPanel.ai ,
Delve.ai , and POPJAM . It runs as both a CLI and a
12-tool MCP server you can drop into Claude Code, Cursor, Windsurf,
or Zed. Install with
- pip install synthpanel[mcp].
+ pip install althing[mcp].
MIT-licensed. Its 3-model ensemble leads the SynthBench leaderboard
at SPS 0.86–0.88 (opinionsqa 0.877, subpop 0.858;
leaderboard generated 2026-07-17).
@@ -225,14 +225,14 @@
That's where an open-source, LLM-agnostic synthetic focus group tool
- starts to matter. Enter SynthPanel .
+ starts to matter. Enter Althing .
2. Why LLM-Agnostic Matters
- SynthPanel is a pure Python library with a provider-agnostic LLM
+ Althing is a pure Python library with a provider-agnostic LLM
client. You set an environment variable, you pick a model alias
(sonnet,
haiku,
@@ -256,7 +256,7 @@
whatever your provider charges, no markup, no seat license, no
per-panel metering. If you have a Claude enterprise deal, use it. If
you have Gemini free-tier credits, use those. Token accounting is
- built in: SynthPanel tracks input, output, cache-read, and
+ built in: Althing tracks input, output, cache-read, and
cache-write tokens separately and emits a per-panel cost total.
What you see is what your provider actually charged.
@@ -274,7 +274,7 @@
Gemini 2.5 Flash, blend at
--models sonnet:0.34,gpt-4o:0.33,gemini:0.33,
and the framework emits per-model distributions and the
- weighted ensemble. This is how SynthPanel tops the SynthBench
+ weighted ensemble. This is how Althing tops the SynthBench
leaderboard: the blended ensemble beats every single model on each
dataset — by roughly 0.03–0.05 SPS — which you cannot get from any
single model alone.
@@ -283,7 +283,7 @@
3. Why YAML Instruments Matter
- Here is a SynthPanel instrument:
+ Here is a Althing instrument:
@@ -331,7 +331,7 @@
It is portable. Bundle an instrument as a "pack"
- (SynthPanel ships eight v3 branching packs —
+ (Althing ships eight v3 branching packs —
churn-diagnosis,
feature-prioritization,
general-survey,
@@ -348,7 +348,7 @@
Closed SaaS competitors typically expose a form-based editor. That
editor is great for non-technical teams composing one-off studies.
It is terrible for research-ops teams who want a reproducible,
- diffable, versionable artifact. That is the gap SynthPanel's
+ diffable, versionable artifact. That is the gap Althing's
YAML-instrument format fills.
@@ -362,7 +362,7 @@
Cursor, Windsurf, Zed) can call them.
- SynthPanel ships an MCP server with twelve tools:
+ Althing ships an MCP server with twelve tools:
run_prompt — one-shot LLM call against any configured model.
@@ -379,8 +379,8 @@
>
{
"mcpServers" : {
- "synth_panel" : {
- "command" : "synthpanel" ,
+ "althing" : {
+ "command" : "althing" ,
"args" : ["mcp-serve" ],
"env" : { "ANTHROPIC_API_KEY" : "sk-..." }
}
@@ -399,7 +399,7 @@
If you came here searching for "MCP server survey research"
- or "MCP server focus group," SynthPanel is the thing you
+ or "MCP server focus group," Althing is the thing you
want to install.
@@ -409,7 +409,7 @@
Synthetic research is useful for exploration, hypothesis generation,
and rapid iteration. It is not a replacement for
- talking to real humans. SynthPanel documents four known limits in
+ talking to real humans. Althing documents four known limits in
its README, and they apply to every tool in this category —
commercial or otherwise:
@@ -454,7 +454,7 @@
6. Quantitative Proof: SynthBench SPS 0.86–0.88
- Claims are cheap. SynthPanel publishes head-to-head results on
+ Claims are cheap. Althing publishes head-to-head results on
>, an open, reproducible benchmark for synthetic-respondent quality.
Its data and scoring code are public — though, in the interest of
full disclosure, SynthBench is a sibling DataViking project operated
- by the SynthPanel maintainers, not an independent third party.
+ by the Althing maintainers, not an independent third party.
SynthBench computes a Synthetic-Parity Score (SPS)
— how closely a synthetic panel's response distribution matches a
real-human control group on the same instrument.
- A 3-model ensemble of SynthPanel personas — the leaderboard’s
- “SynthPanel Ensemble (3-model)” entry, an equal-weight
+ A 3-model ensemble of Althing personas — the leaderboard’s
+ “Althing Ensemble (3-model)” entry, an equal-weight
blend of Claude Haiku 4.5, Gemini 2.5 Flash Lite, and GPT-4o-mini,
run via
- synthpanel panel run --models haiku:0.33,gemini-flash-lite:0.33,gpt-4o-mini:0.34 --blend
+ althing panel run --models haiku:0.33,gemini-flash-lite:0.33,gpt-4o-mini:0.34 --blend
— leads the current SynthBench leaderboard (generated 2026-07-17) at
SPS 0.877 on opinionsqa and
0.858 on subpop (0.813 on
@@ -496,7 +496,7 @@
If you need an open-source synthetic focus group
tool, an LLM-agnostic focus group tool , an
open-source AI persona survey runner, or an
- MCP server for survey research — SynthPanel is one
+ MCP server for survey research — Althing is one
pip
away.
@@ -504,31 +504,31 @@
class="mt-6 overflow-x-auto rounded-lg border border-slate-800 bg-slate-950/70 p-5 font-mono text-sm leading-relaxed"
>
# Full install with MCP server support
-pip install synthpanel[mcp]
+pip install althing[mcp]
# Set a provider key (any of these works)
export ANTHROPIC_API_KEY=sk-...
# Run a panel from a bundled instrument
-synthpanel panel run --personas examples/personas.yaml --instrument pricing-discovery
+althing panel run --personas examples/personas.yaml --instrument pricing-discovery
# Or start the MCP server for your AI coding agent
-synthpanel mcp-serve
+althing mcp-serve
Homepage:
- synthpanel.dev
+ althing.dev
· Repo:
github.com/DataViking-Tech/SynthPanel github.com/DataViking-Tech/Althing
· Benchmark:
synthbench.org
· Full MCP docs:
docs/mcp.md .
@@ -569,8 +569,8 @@
-
-
+
+
Home
MCP server
@@ -584,10 +584,10 @@
@@ -608,15 +608,15 @@
@@ -127,7 +127,7 @@
Calibration is how a persona pack proves its fit to a known human
- baseline. Run synthpanel pack calibrate
+ baseline. Run althing pack calibrate
and the result is written back into the pack YAML so the manifest is
self-describing.
@@ -143,7 +143,7 @@
-
synthpanel pack calibrate <PACK_YAML>
+ althing pack calibrate <PACK_YAML>
--against DATASET:QUESTION # e.g. gss:HAPPY (v1 allowlist: gss, ntia)
[--n 50] # panel size
[--models MODELS] # default: panel run default
@@ -171,14 +171,14 @@
extractor: pick_one:auto-derived
panelist_cost_usd: 0.6451
calibrated_at: 2026-07-16T14:23:00Z
- synthpanel_version: 1.5.7
- methodology_url: https://synthpanel.dev/docs/calibration
+ althing_version: 1.5.7
+ methodology_url: https://althing.dev/docs/calibration
The 4-model models: mix above is
an example blend, not the SynthBench leaderboard ensemble —
- the leaderboard’s “SynthPanel Ensemble (3-model)”
+ the leaderboard’s “Althing Ensemble (3-model)”
entry is an equal-weight blend of Claude Haiku 4.5, Gemini 2.5 Flash
Lite, and GPT-4o-mini.
@@ -231,7 +231,7 @@
JSD is computed locally via the same metric the convergence tracker
- uses (see src/synth_panel/convergence.py);
+ uses (see src/althing/convergence.py);
the pack YAML is the only durable
artifact — calibration does not phone home and is distinct from
--submit-to-synthbench.
@@ -325,12 +325,12 @@
$
SYNTHBENCH_ALLOW_GATED=1
- synthpanel pack calibrate ... --against wvs:Q1
+ althing pack calibrate ... --against wvs:Q1
Copy
@@ -377,7 +377,7 @@
5
The resulting JSD, plus provenance (extractor, models, cost,
- timestamp, synthpanel version), is merged into the pack YAML's
+ timestamp, althing version), is merged into the pack YAML's
calibration: list.
Re-running against the same (dataset, question)
pair replaces the prior entry rather than
@@ -438,9 +438,9 @@
The command requires the
- synthpanel[convergence] extra
+ althing[convergence] extra
(for the synthbench baseline loader).
- Install with pip install 'synthpanel[convergence]'
+ Install with pip install 'althing[convergence]'
if not already present.
@@ -470,7 +470,7 @@ MCP Server
@@ -487,7 +487,7 @@
Source docs
@@ -534,8 +534,8 @@
Report an issue
-
-
+
+
Home
MCP server
@@ -549,10 +549,10 @@
@@ -573,15 +573,15 @@ DataViking-Tech/Althing
+althing pack calibrate
--against DATASET:QUESTION # e.g. gss:HAPPY (v1 allowlist: gss, ntia)
[--n 50] # panel size
[--models MODELS] # default: panel run default
@@ -34,11 +34,11 @@ calibration:
extractor: pick_one:auto-derived
panelist_cost_usd: 0.6451
calibrated_at: 2026-07-16T14:23:00Z
- synthpanel_version: 1.5.7
- methodology_url: https://synthpanel.dev/docs/calibration
+ althing_version: 1.5.7
+ methodology_url: https://althing.dev/docs/calibration
```
-The 4-model `models:` mix above is an example blend, *not* the SynthBench leaderboard ensemble — the leaderboard’s “SynthPanel Ensemble (3-model)” entry is an equal-weight blend of Claude Haiku 4.5, Gemini 2.5 Flash Lite, and GPT-4o-mini.
+The 4-model `models:` mix above is an example blend, *not* the SynthBench leaderboard ensemble — the leaderboard’s “Althing Ensemble (3-model)” entry is an equal-weight blend of Claude Haiku 4.5, Gemini 2.5 Flash Lite, and GPT-4o-mini.
## What JSD means
@@ -52,7 +52,7 @@ Calibration reports **Jensen-Shannon divergence** between the pack's extracted a
| `0.30–0.50` | Weak — major disagreement on at least one mode. |
| `> 0.50` | Effectively uncalibrated. |
-JSD is computed locally via the same metric the convergence tracker uses (see `src/synth_panel/convergence.py`); the pack YAML is the **only** durable artifact — calibration does not phone home and is distinct from `--submit-to-synthbench`.
+JSD is computed locally via the same metric the convergence tracker uses (see `src/althing/convergence.py`); the pack YAML is the **only** durable artifact — calibration does not phone home and is distinct from `--submit-to-synthbench`.
## When to calibrate
@@ -79,7 +79,7 @@ Other datasets (OpinionsQA, PewTech, GlobalOpinionQA, WVS, …) are **gated** fo
To override the allowlist for internal use:
-$ SYNTHBENCH_ALLOW_GATED=1 synthpanel pack calibrate ... --against wvs:Q1
+$ SYNTHBENCH_ALLOW_GATED=1 althing pack calibrate ... --against wvs:Q1
## Methodology
@@ -93,7 +93,7 @@ For each calibration run:
- 4 The model distribution is compared against the baseline's `human_distribution` via Jensen-Shannon divergence.
-- 5 The resulting JSD, plus provenance (extractor, models, cost, timestamp, synthpanel version), is merged into the pack YAML's `calibration:` list. Re-running against the same `(dataset, question)` pair **replaces** the prior entry rather than appending, so the list is always a clean record of one-result-per-baseline.
+- 5 The resulting JSD, plus provenance (extractor, models, cost, timestamp, althing version), is merged into the pack YAML's `calibration:` list. Re-running against the same `(dataset, question)` pair **replaces** the prior entry rather than appending, so the list is always a clean record of one-result-per-baseline.
## Idempotence and re-runs
@@ -109,7 +109,7 @@ For each calibration run:
- Calibration measures distributional fit on **one** answer distribution. A low JSD on `gss:HAPPY` does not imply low JSD on a different question — calibrate against multiple baselines if you need broad coverage.
-- The command requires the `synthpanel[convergence]` extra (for the `synthbench` baseline loader). Install with `pip install 'synthpanel[convergence]'` if not already present.
+- The command requires the `althing[convergence]` extra (for the `synthbench` baseline loader). Install with `pip install 'althing[convergence]'` if not already present.
## See also
@@ -119,13 +119,13 @@ For each calibration run:
Run calibrated panel runs via the MCP tools from your AI editor.
-### [Source docs](https://github.com/DataViking-Tech/SynthPanel/blob/main/docs/calibration.md)
+### [Source docs](https://github.com/DataViking-Tech/Althing/blob/main/docs/calibration.md)
→
The canonical `docs/calibration.md` in the GitHub repo.
-### [Report an issue](https://github.com/DataViking-Tech/SynthPanel)
+### [Report an issue](https://github.com/DataViking-Tech/Althing)
→
diff --git a/site/docs/index.html b/site/docs/index.html
index dd66662f..073793b6 100644
--- a/site/docs/index.html
+++ b/site/docs/index.html
@@ -4,36 +4,36 @@
- Documentation — synthpanel · Run synthetic focus groups with any LLM
+ Documentation — althing · Run synthetic focus groups with any LLM
-
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
@@ -78,7 +78,7 @@
href="/"
class="inline-flex items-center gap-1 text-slate-400 transition hover:text-emerald-300"
>
- ← synthpanel.dev
+ ← althing.dev
@@ -97,7 +97,7 @@
Documentation
- Everything for running synthetic focus groups with synthpanel —
+ Everything for running synthetic focus groups with althing —
the CLI reference and MCP server guide live on this site; the full
docs set (methodology, response contract, production operations, and
more) is maintained in the GitHub repo.
@@ -150,7 +150,7 @@
Pack calibration
Calibrate a persona pack against a known human baseline with
- synthpanel pack calibrate —
+ althing pack calibrate —
JSD interpretation and methodology.
@@ -180,7 +180,7 @@ Recommended models
The canonical, always-current documentation lives in the repo’s
docs/ directory Recommended models
- agent-quickstart.md
+ agent-quickstart.md
— end-to-end walkthrough: install → verify → dry-run → run → save → emit JSON, on both CLI and MCP surfaces.
- mcp.md
+ mcp.md
— full MCP tool schemas, resources, prompt templates, and the model-resolution order.
- response-contract.md
+ response-contract.md
— the frozen v1.0.0 response envelope, field by field (panel_verdict, typed errors, schema_version).
- structured-polling.md
+ structured-polling.md
— schema-enforced polling patterns (pick-one, Likert, confidence, tagged themes), the agent default.
- production-operations.md
+ production-operations.md
— running panels in production: checkpointing, cost gates, failure budgets, and observability.
- methodology.md
+ methodology.md
— how panels are constructed, synthesized, and where synthetic research is (and isn’t) trustworthy.
- ensemble.md
+ ensemble.md
— multi-model ensemble blending (--models / --blend) and the public ensemble API.
- reproducibility.md
+ reproducibility.md
— seeds, model pinning, and what “reproducible” can and cannot mean across providers.
- model-packs.md
+ model-packs.md
— bundled persona and instrument packs, and how to author your own.
- registry.md
+ registry.md
— the decentralized pack registry: pack import gh:<user>/<repo>, search, and verification.
- migration-v1.md
+ migration-v1.md
— migrating from v0.12 to the frozen v1.0.0 contract.
- synthbench-integration.md
+ synthbench-integration.md
— inline calibration against SynthBench baselines and opt-in leaderboard submission.
@@ -267,8 +267,8 @@ Recommended models
-
-
+
+
Home
MCP server
@@ -282,10 +282,10 @@
@@ -306,15 +306,15 @@
@@ -126,7 +126,7 @@
panel run reference
- Full reference for synthpanel panel run.
+ Full reference for althing panel run.
Covers the advanced flags for multi-model panels, persona variants,
structured extraction, synthesis tuning, convergence auto-stop,
checkpointing, and SynthBench integration.
@@ -172,7 +172,7 @@
Weighted per-persona assignment