estimate-maestro
estimate-maestro
개인용 MCP 서버이자 명령줄 도구로, 추정치와 실제 소요 시간을 기록하여 추정치를 나중에 감정이 아닌 결과와 대조할 수 있게 합니다.
이것은 추정 보정을 위한 데이터 수집 도구이지, 추정기가 아닙니다. 어떤 것도 추정해 주지 않습니다. 작업에 대해 추정한 값, 계획이 실제로 어떻게 되었는지, 작업에 실제로 걸린 벽시계 시간을 기록합니다. 그 기록으로 무엇을 할지 — 비교, 편향 관찰, 특정 종류의 작업에 대해 일관되게 낙관적이었다고 판단하는 것 — 는 여러분과 나중에 저장소를 읽는 무엇이든 몫입니다. 도구의 역할은 정직하게 기록하는 데서 끝납니다.
모델
네 종류의 것이 기록됩니다:
Effort — 자체적으로 추적할 가치가 있는 작업 조각: 풀 리퀘스트, 메가 PR, 계획과 크기가 있는 모든 것. effort는 계획 산출물(스펙,
.PR.md, 계획이 담긴 무엇이든)과 초기 추정치가 생기는 순간부터 존재합니다. 그 이전에는 아직 기록할 것이 없습니다.Slice — effort의 조각, 보통 하위 PR. 슬라이스는 추가되거나, 풀 리퀘스트에 대해 닫히거나, 삭제되거나, 이름이 바뀝니다. effort가 시작되기 전에 추가된 슬라이스는 원래 계획의 일부이고, 이후에 추가된 것은 범위 증가이며, 둘은 기록에서 구분 가능하게 유지됩니다.
Interval — 일반적으로 슬라이스에 대해 시계를 켜둔 시간 범위. 인터벌은 수동으로 닫히거나, 세션이 시계가 여전히 돌아가는 상태로 끝나면 자동으로 닫히거나, 아무것도 시계를 켜지 않았을 때 커밋 타임스탬프에서 사후에 파생됩니다.
Absence — 전혀 작업하지 않은 시간: 휴일, 약속, 관련 없는 회의. 부재는 소급하여 기록되며 그렇게 하는 것이 예상됩니다. 겹치는 인터벌에서 차감됩니다.
Related MCP server: time-tracker-ai-mcp
추정치: 스토리 포인트의 3점 추정
모든 추정치는 PERT 트리플 — 낙관적, 가능, 비관적 — 이며 추상적인 포인트 척도로 주어지고 절대 시간 단위가 아닙니다. 기대값과 표준편차는 읽을 때 트리플에서 파생됩니다. "추정치는 N이다"라는 단일 숫자는 저장되지 않습니다. 단일 숫자는 추정치를 사실이 아닌 추정치로 만드는 불확실성을 버리기 때문입니다.
포인트는 손에 있는 작업을 비슷한 형태의 이전 effort와 비교하여 고정되며, 느껴지는 시간 수를 머릿속에서 포인트로 변환하는 것이 아닙니다. 추상적인 척도의 핵심은 실제 기간을 아직 모르는 effort들 간에 같은 것끼리 비교하는 것입니다.
effort는 두 번 추정됩니다:
초기 추정치는 처음 작성된 계획에 대해, 계획이 시작된 슬라이스 수와 동일한 슬라이스 수로 만들어집니다.
최종 추정치는 회고에서 실제로 드러난 계획에 대해 만들어집니다 — 그 과정에서 삽입된 모든 슬라이스를 포함합니다. 이것은 반사실적입니다: "이것이 실제로 어떻게 진행되었는지 지금 아는 모든 것을 고려하면, 무엇으로 추정했을까?" — 결코 "얼마나 걸렸나?"가 아니며, 어떤 것의 측정도 아닙니다.
추정을 두 번으로 나누는 것은 추정이 잘못될 수 있는 두 가지 방식을 사후에 분리할 수 있게 만듭니다. 초기 추정은 재고 오류 때문에 잘못될 수 있습니다 — 아무도 몰랐던 작업이 존재했거나, 존재한다고 가정한 작업이 실제로는 없었던 경우. 실제로 드러난 계획에 대해 만들어진 최종 추정은 크기 오류를 분리합니다 — 처음부터 알려져 있었지만 단순히 잘못 판단된 항목들. effort당 단일 숫자는 둘을 혼동합니다. 패스당 두 개의 숫자는 둘을 분리합니다.
수정된 추정치는 effort 중간에도 기록될 수 있습니다 — 일반적으로 원래 계획에 없던 슬라이스가 삽입될 때 — 회고를 기다리지 않고.
시간 모델: 정상적인 하루가 가정됩니다
정상적인 근무일이 기본적으로 가정되며, 그로부터의 편차만 기록됩니다. 출퇴근 기록은 예외이지 일상이 아닙니다 — 도구는 매일 8시간 동안 스톱워치가 돌아가기를 기대하지 않습니다. 구체적으로:
수동으로 기록된 시간은 그 시간대가 무엇이든 전부 계산됩니다. 저녁과 주말 포함: 토요일 22:00에 출근 기록을 했다면 그것은 실제 시간이며 그대로 기록되며, 근무 시간 조정이 적용되지 않습니다.
근무 시간 모델은 실제로 기록된 시간이 없는 곳에만 적용됩니다. 정확히 두 곳에서 사용됩니다:
잊은 타이머 고정. 세션이 시계가 여전히 돌아가는 상태로 끝나면, 인터벌은 구성된 근무일 종료 시점(또는 구성된 근무일과 시간 밖에서는 고정된 세션 길이로 상한)에서 닫히며, 무기한 열려 있거나 분 단위로 추측되지 않습니다.
커밋 타임스탬프에서 인터벌 재구성 슬라이스에 대해 아무것도 시계를 켠 적이 없을 때. 가까운 커밋 무리는 파생된 작업 세션이 되며, 근무 시간 모델을 사용하여 그 사이의 시간 중 얼마가 작업으로 간주되고 밤샘 간격으로 간주되지 않는지 결정합니다.
기록된 부재는 겹치는 인터벌 — 시계가 켜진 것이든 파생된 것이든 — 에서 차감되며, 수동으로 시계가 켜진 인터벌에서는 전액, 파생된 인터벌에서는 근무 시간 모델을 통해 차감됩니다.
도구 범주와 오염 규칙
MCP 서버가 노출하는 모든 도구는 정확히 한 범주에 속합니다:
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, 추정을 하는 동안 비교를 위해 이전 effort를 보여줍니다.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를 읽으십시오.
변수 | 기본값 | 의미 |
|
| 저장소 디렉터리 경로. |
|
| 근무일 시작 (ISO 8601 시간). |
|
| 근무일 종료 (ISO 8601 시간). |
|
| 매일 점심 휴식 시작, 작업 초에서 제외. |
|
| 매일 점심 휴식 종료. |
|
| 근무일로 계산되는 쉼표로 구분된 요일 (월요일 |
|
| 근무 시간 창 밖에서 시작하는 고정된 세션에 주어지는 최대 길이. |
|
| 파생된 세션에서 가장 이른 커밋 전에 추가되는 시간, 첫 커밋 전에 수행된 작업을 포함. |
|
| 커밋 사이의 작업 시간 간격으로, 이를 초과하면 파생된 세션이 종료되고 새 세션이 시작된 것으로 간주. |
|
|
|
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. 추정 대화의 일부로만 의미가 있는 작업 — effort 시작, 추정 수정, 최종 계획 기록, 커밋 수집 — 은 의도적으로 MCP 도구일 뿐 CLI 명령이 아닙니다. 그런 작업은 비교 가능한 이전 effort를 보여주는 세션 안에서 일어나도록 되어 있으며, 그 맥락 없이 입력하는 단순한 명령이 아닙니다.
종료 코드
코드 | 의미 |
| 성공. |
| 오류 발생. |
|
|
설치
다음 중 어떤 것도 여러분을 위해 실행되지 않았습니다 — 아래 명령을 복사하여 직접 실행하십시오.
MCP 서버를 등록하십시오:
claude mcp add --scope user maestro-estimate -- uv --directory ~/mcp/estimate-maestro run estimate-maestro두 스킬을 개인 스킬 디렉터리에 심볼릭 링크하십시오:
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 저장소로 만드세요. 그 파일들은 일반 텍스트이고 추가 전용(append-only)이어서 커밋하고 여러 머신 사이로 옮겨 다닐 수 있으며, 기록하는 내용의 유일하게 남는 사본입니다. 그 안에서 잃어버리거나 잘못된 숫자는 다른 어디에서도 재구성할 수 없습니다. 비공개로 유지하세요. 프로젝트 이름, 브랜치 이름, 작업에 걸린 시간이 들어 있으며, 이 중 어느 것도 공개 저장소에 있어서는 안 됩니다.
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두 훅 스크립트를 ~/.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" }
]
}
]
}
}~/.claude/settings.json에 이미 hooks 블록이 있다면 덮어쓰지 말고 기존 블록에 병합하세요.
개발
uv sync --locked
uv run ruff format --check
uv run ruff check
uv run pyright
uv run pytest src/ -vAvailable Tools
21 toolsadd_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
Scored across 21 tools
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.
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.
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.
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
Related MCP Connectors
Personal time tracker: start timers, log time and summarize your hours by activity.
Time tracking you talk to: log, check and fix your work hours from your AI assistant.
Save and retrieve your chosen context, manage shared workspaces, and track project time.
Privacy-first work tracking with summaries, reports, coaching, and AI-ready long-term memory.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables time tracking in Tempo with automatic timesheet generation from git commits, worklog management with roles and accounts, and integration with Jira for seamless project time logging.1MIT
- AlicenseAqualityCmaintenanceEnables tracking work time with start/stop timers, logging entries, and generating reports.48 npm28 PyPIMIT
- FlicenseNot gradedqualityBmaintenanceEnables tracking worked hours by client, project, and task, with monthly/daily reports and natural language interaction through Claude.-
- AlicenseNot gradedqualityCmaintenanceEnables local-first time tracking with timers and time entries stored in a SQLite database that sync to Intervals in the background, with local-only reporting and queries.23 npmMIT