Skip to main content
Glama

estimate-maestro

個人的なMCPサーバー兼コマンドラインツールで、見積もりと実経過時間を記録し、見積もりを最終的に「感覚」ではなく「結果」と照合できるようにするためのものです。

これは見積もりキャリブレーションのためのデータ収集ツールであり、見積もりツールではありません。 何かの見積もりを自動で行うことは一切ありません。記録するのは、ある作業に対してあなたが立てた見積もり、計画が実際にどうなったか、そしてその作業に実際にかかった実時間です。その記録をどう使うか(比較する、ずれに気づく、ある種の作業について一貫して楽観的だったと判断するなど)は、あなた自身と、後でストアを読み出すものに委ねられています。このツールの役割は、正直に記録するところまでで終わりです。

モデル

記録されるものは4種類あります。

  • Effort(エフォート) — 単独で追跡する価値のある作業のかたまり。プルリクエスト、メガPR、計画と規模を持つものすべてが該当します。エフォートは、計画アーティファクト(仕様書、.PR.md、計画が置かれているもの)と初期見積もりが存在した時点から存在します。それ以前は、まだ記録すべきものはありません。

  • Slice(スライス) — エフォートの一部で、通常はサブPRです。スライスは追加、プルリクエストに対するクローズ、破棄、リネームが行われます。エフォート開始前に追加されたスライスは当初計画の一部であり、開始後に追加されたものはスコープの拡大であり、この2つは記録上区別可能なまま保持されます。

  • Interval(インターバル) — クロックインされた時間の区間で、通常はスライスに対して行われます。インターバルは手動でクローズされるか、セッション終了時に時計がまだ動いている場合は自動的にクローズされるか、何もクロックインされていなかった場合はコミットタイムスタンプから事後的に導出されます。

  • Absence(欠勤) — まったく作業しなかった時間。休日、予定、無関係な会議などです。欠勤は事後的に記録され、それが想定されています。欠勤は重なるインターバルから差し引かれます。

Related MCP server: time-tracker-ai-mcp

見積もり: ストーリーポイントによる3点見積もり

すべての見積もりはPERTトリプル(楽観値、最頻値、悲観値)であり、抽象的なポイントスケールで与えられ、時間単位では決してありません。期待値と標準偏差は読み出し時にトリプルから導出されます。「見積もりはNである」という単一の数値はどこにも保存されません。なぜなら、裸の数値は、それが事実ではなく見積もりであることを示す不確実性を捨て去ってしまうからです。

ポイントは、手元の作業を同様の形状の過去のエフォートと比較することでアンカーされ、頭の中で感じた時間数をポイントに変換するのではありません。抽象スケールの要点は、実際の期間がまだわからないエフォート同士を、同種のもの同士で比較することにあります。

エフォートは2回見積もられます。

  • 初期見積もりは、最初に書かれた計画に対して、計画が開始したときと同じスライス数で行われます。

  • 最終見積もりは、レトロスペクティブで、実際に結果として得られた計画(途中で挿入されたすべてのスライスを含む)に対して行われます。これは反事実的なものです。「これが実際にどう転んだかを今すべて知っているとしたら、あなたは何と見積もっただろうか?」という問いであり、「どれだけ時間がかかったか?」でも、何かの測定でもありません。

見積もりを2回に分けることで、見積もりが間違う2つの方法を事後に分離できるようになります。初期パスは在庫エラーによって間違う可能性があります。つまり、まだ誰も知らない作業が存在した、または存在すると想定された作業が実際には存在しなかった、という場合です。実際に結果として得られた計画に対して行われる最終パスは、サイズエラーを分離します。つまり、最初から知られていた項目を単に誤って判断した場合です。エフォートごとに単一の数値ではこの2つが混同されますが、パスごとに2つの数値があれば、それらを分離できます。

また、エフォート途中で改訂見積もりを記録することもできます(通常は当初計画にないスライスが挿入されたとき)。レトロスペクティブを待つ必要はありません。

時間モデル: 通常の1日が想定される

通常の勤務日がデフォルトで想定され、そこからの逸脱のみが記録されます。 クロックインとクロックアウトは例外であり、日常的なものではありません。このツールは毎日8時間ストップウォッチが動いていることを想定していません。具体的には:

  • 手動でクロックされた時間は、それが何時であろうと全額カウントされます。 夜間や週末も含みます。土曜日の22:00にクロックインしたなら、それは実際の時間であり、そのまま記録され、勤務時間の調整は適用されません。

  • 勤務時間モデルは、実際に時間が記録されなかった場所にのみ適用されます。 使用されるのは正確に2か所です:

    • 忘れられたタイマーのクランプ。 セッションが時計がまだ動いたまま終了した場合、インターバルは設定された勤務日の終了時刻(または設定された勤務日・時間外では、固定のセッション長に上限)でクローズされ、無期限に開いたままになったり、分単位で推測されたりすることはありません。

    • コミットタイムスタンプからのインターバル再構築。 スライスに対して何もクロックインされなかった場合。近接したコミットのクラスターは導出された作業セッションになり、勤務時間モデルを使用して、それらの間のスパンのうちどれだけが作業としてカウントされ、どれだけが一晩のギャップとしてカウントされるかを決定します。

記録された欠勤は、それが重なる任意のインターバル(クロックされたもの、導出されたもの)から差し引かれます。手動でクロックされたインターバルでは全額、導出されたインターバルでは勤務時間モデルを通じて差し引かれます。

ツールカテゴリと汚染ルール

MCPサーバーが公開するすべてのツールは、正確に1つのカテゴリに分類されます:

  • recording(記録) — start_effort、add_slice、close_slice、drop_slice、rename_slice、clock_in、clock_out、annotate_interval、repair_interval、record_absence、record_revision、record_final_plan、harvest_commits、record_landed_commit、remap_commits、finish_effort。

  • estimation(見積もり) — reference_efforts。見積もりを作成している間、比較用に過去のエフォートを表示します。

  • status(ステータス) — current。何がクロックインされていて、いつからかを報告します。

  • calibration(キャリブレーション) — effort_table、effort_detail、summary。蓄積された記録を読み出します。

recording、estimation、statusツールは、期間や集計値を返すことはありません。calibrationツールのみが返すことができます。 これは構造的に強制されます。recording、estimation、statusツールで使用されるすべてのレスポンスモデルは、hours、minutes、duration、wall、average、shareなどの単語を含むフィールド名がないかチェックされ、見つかった場合はチェックが失敗します。

その理由は整理整頓のためではありません。実際の作業時間を見た後に行われた見積もりは、その時間のアンカーされたエコーであり、独立した判断ではありません。あなたが生成する数値は、ちょうど答えを見たばかりであるために汚染されています。汚染ルールにより、見積もりが作成されている間や時計が実行されている間、壁時計の数値がツールのレスポンスに表示されることは決してなく、初期対最終の比較が正直に保たれます。calibrationツールは、見積もりが完了した後に、まさにそれらの数値を報告することが目的であるため、免除されます。

環境変数

すべてオプションです。すべてにデフォルトがあります。このリストと矛盾する場合は、src/estimate_maestro/config.pyを参照してください。

変数

デフォルト

意味

ESTIMATE_MAESTRO_STORE

$XDG_DATA_HOME/estimate-maestro、フォールバックとして~/.local/share/estimate-maestro

ストアディレクトリへのパス。

ESTIMATE_MAESTRO_DAY_START

09:00

勤務日の開始時刻(ISO 8601形式)。

ESTIMATE_MAESTRO_DAY_END

17:00

勤務日の終了時刻(ISO 8601形式)。

ESTIMATE_MAESTRO_LUNCH_START

12:00

毎日の昼休みの開始時刻。勤務秒数から除外されます。

ESTIMATE_MAESTRO_LUNCH_END

13:00

毎日の昼休みの終了時刻。

ESTIMATE_MAESTRO_WORKDAYS

0,1,2,3,4

勤務日としてカウントされる曜日をカンマ区切りで指定(月曜0 … 日曜6)。

ESTIMATE_MAESTRO_OFF_HOURS_SESSION_CAP_MINUTES

240(4時間)

勤務時間外に開始されたクランプされたセッションに与えられる最大長。

ESTIMATE_MAESTRO_DERIVE_LEAD_IN_MINUTES

30

導出されたセッションの最初のコミットの前に追加される時間。最初のコミット前の作業をカバーします。

ESTIMATE_MAESTRO_DERIVE_SESSION_GAP_MINUTES

120(2時間)

コミット間の作業時間のギャップ。これを超えると、導出されたセッションは終了し、新しいセッションが開始されたと見なされます。

ESTIMATE_MAESTRO_MINIMUM_EFFORTS

5

summaryが数値を報告する(正直な拒否ではなく)ために必要な記録済みエフォートの最小数。

ESTIMATE_MAESTRO_DERIVE_LEAD_IN_MINUTESはESTIMATE_MAESTRO_DERIVE_SESSION_GAP_MINUTESを超えてはなりません。そうでない場合、サーバーは起動を拒否します。

コマンドラインツール

estimate-maestro-cliは、会話を必要としない日常的な記録アクションをカバーします: clock-in、clock-out、current、record-absence、effort-table、summary。見積もり会話の一部としてのみ意味を持つアクション(エフォートの開始、見積もりの改訂、最終計画の記録、コミットの収穫)は、意図的にMCPツールのみであり、CLIコマンドではありません。それらは、比較可能な過去のエフォートを表示するセッション内で行われることを意図しており、そのコンテキストなしで入力される裸のコマンドではありません。

終了コード

コード

意味

0

成功。

1

エラーが発生しました。

3

clock-outのみ: 何もクロックインされていません。想定内で頻繁に発生します。失敗ではありません。clock-outを自動フックに配線するスクリプトは、3を0と同じように扱うべきです。

インストール

以下のいずれもあなたのために実行されていません。以下のコマンドをコピーして自分で実行してください。

MCPサーバーを登録します:

claude mcp add --scope user maestro-estimate -- uv --directory ~/mcp/estimate-maestro run estimate-maestro

2つのスキルを個人スキルディレクトリにシンボリックリンクします:

ln -s ~/mcp/estimate-maestro/skills/recording-work-time ~/.claude/skills/recording-work-time
ln -s ~/mcp/estimate-maestro/skills/estimating-work ~/.claude/skills/estimating-work

ストアをgitリポジトリにします。そのファイルはプレーンテキストで追記専用のため、コミットしてマシン間を移動でき、記録された内容の唯一の生き残りコピーとなります。そこで失われたり誤ったりした数値は、他のどこからも再構築できません。プライベートに保ってください。プロジェクト名、ブランチ名、所要時間が含まれており、いずれも公開リポジトリに置くべきものではありません。

mkdir -p ~/.local/share/estimate-maestro
git -C ~/.local/share/estimate-maestro init

デフォルトのストア場所はXDG Base Directory Specificationに従い、設定は不要です。ストアを別の場所に置きたい場合のみESTIMATE_MAESTRO_STOREを設定してください。たとえば他の個人リポジトリと並べて、コミットとプッシュを忘れないようにしやすくするためです。サーバーとシェルの両方から見える必要があるため、両方が読み取る場所(通常はシェルプロファイル)に置いてください。

export ESTIMATE_MAESTRO_STORE=~/somewhere/else

2つのフックスクリプトを~/.claude/settings.jsonに配線します。hooks/session-end.shをSessionEndフックとして(忘れられたタイマーを閉じ、設定された勤務日にクランプ)、hooks/session-start.shをSessionStartフックとして(タイマーがすでに実行中かどうかを報告):

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          { "type": "command", "command": "~/mcp/estimate-maestro/hooks/session-start.sh" }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          { "type": "command", "command": "~/mcp/estimate-maestro/hooks/session-end.sh" }
        ]
      }
    ]
  }
}

すでにhooksブロックがある場合は、~/.claude/settings.jsonの既存のhooksブロックに上書きではなくマージしてください。

開発

uv sync --locked
uv run ruff format --check
uv run ruff check
uv run pyright
uv run pytest src/ -v

Available Tools

21 tools
add_sliceC

Add a slice. One added while the effort is active is scope growth.

Inputs: title (required), effort (required). Returns: recorded, identifier

annotate_intervalC

Attach meeting participants or a note to an interval after the fact.

Inputs: effort (required), interval (required), note, external, +2 more. Returns: recorded, identifier

clock_inC

Start an interval. Refused if one is already open.

Inputs: effort (required), kind, note, external, +3 more. Returns: recorded, identifier

clock_outC

Close the open interval.

Inputs: at, note. Returns: recorded, identifier

close_sliceC

Close a slice against its pull request.

Inputs: effort (required), work_slice (required), pull_request (required). Returns: recorded, identifier

currentB

What is clocked in, and since when.

Inputs: no named parameters. Returns: since, effort, interval, work_slice

drop_sliceC

Drop a slice that turned out to be unnecessary.

Inputs: effort (required), reason (required), work_slice (required). Returns: recorded, identifier

effort_detailC

One effort's full event history.

Inputs: effort (required). Returns: row, meta, slices, commits, +2 more

effort_tableC

One near-raw row per effort: estimates, wall hours, slice counts.

Inputs: no named parameters. Returns: result

finish_effortC

Mark an effort done.

Inputs: effort (required). Returns: recorded, identifier

harvest_commitsC

Copy commit metadata from a working tree into the store.

Inputs: path (required), since (required), until (required), effort (required), +1 more. Returns: recorded, identifier

record_absenceC

Declare time not spent working. Retroactive by design.

Inputs: kind (required), stop (required), start (required), note. Returns: recorded, identifier

record_final_planD

Record the final plan and the counterfactual estimate against it.

Inputs: effort (required), likely (required), plan_path (required), rationale (required), +3 more. Returns: recorded, identifier

record_landed_commitC

Record the durable commit that landed on the default branch.

Inputs: effort (required), identifier (required), repository (required), work_slice (required). Returns: recorded, identifier

record_revisionC

Record a revised estimate, typically when a slice is inserted.

Inputs: effort (required), likely (required), rationale (required), optimistic (required), +1 more. Returns: recorded, identifier

reference_effortsC

Prior efforts with their summaries and estimates, for comparison. No actuals.

Inputs: kind, limit. Returns: result

remap_commitsC

Map a rewritten commit id onto its replacement.

Inputs: new (required), old (required), effort (required), reason (required). Returns: recorded, identifier

rename_sliceD

Rename a slice.

Inputs: title (required), effort (required), work_slice (required). Returns: recorded, identifier

repair_intervalB

Correct an interval's bounds. Appends; never rewrites.

Inputs: effort (required), interval (required), stop, start. Returns: recorded, identifier

start_effortC

Create an effort from a plan artefact and an initial PERT estimate.

Inputs: kind (required), title (required), likely (required), plan_path (required), +5 more. Returns: recorded, identifier

summaryB

Aggregate calibration, or an honest refusal when there is too little data.

Inputs: no named parameters. Returns: note, efforts_counted, mean_hours_per_point, mean_inventory_growth, +2 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.8/5.0

    Scored across 21 tools

    Disambiguation5/5

    Every tool has a clearly distinct purpose. Even overlapping domains like commits (harvest, record, remap) and intervals (clock, annotate, repair) are separated by specific actions and targets. No two tools could be easily confused for the same operation.

    Naming Consistency4/5

    The majority of tools follow a consistent verb_noun pattern (e.g., repair_interval, start_effort, add_slice). A few query tools are named as nouns (current, summary, effort_table, effort_detail), which is a minor deviation but still readable and sensible for retrieval operations.

    Tool Count4/5

    With 21 tools, the surface is substantial but justified by the domain's complexity—covering efforts, intervals, slices, commits, estimates, and queries. Each tool adds distinct functionality, though the count is on the higher end and could feel heavy for simpler use cases.

    Completeness5/5

    The toolset provides comprehensive lifecycle coverage: starting and finishing efforts, managing slices (add/close/drop/rename), tracking time (clock in/out, absence), revising estimates, recording commits, and rich reporting (current, table, detail, summary). No obvious gaps or dead ends are apparent.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers