@wind_mask/aw-watcher-agent-pi

Pi extension for ActivityWatch session tracking — records code agent sessions, models, token usage, and costs

Packages

Package details

extension

Install @wind_mask/aw-watcher-agent-pi from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@wind_mask/aw-watcher-agent-pi
Package
@wind_mask/aw-watcher-agent-pi
Version
0.1.5
Published
May 21, 2026
Downloads
607/mo · 3/wk
Author
wind_mask
License
MIT
Types
extension
Size
26.8 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    ".pi/extensions"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

aw-watcher-agent

!!!本项目是纯粹的vibe coding产物,我尽可能确保其可用性和正确性,但是不对此有任何保障。!!!

English | 中文

Overview

ActivityWatch watcher for code-agent sessions. It records high-level AI coding session activity from code agent into ActivityWatch without storing prompt text or tool-call details.

概览

aw-watcher-agent 是一个面向 code agent 会话的 ActivityWatch watcher。它可以把 code agent 中的 AI 编码会话记录到 ActivityWatch,但不会保存 prompt 文本、assistant 回复文本或工具调用详情。


What it records

aw-watcher-agent tracks session-level metadata only:

  • code agent name (pi)
  • project directory/name
  • session duration via ActivityWatch heartbeats
  • current/final model
  • total token usage and cost
  • per-model token/cost breakdown for sessions that use multiple models

It does not record:

  • prompt text
  • assistant response text
  • tool-call arguments/results
  • file contents

记录哪些数据

aw-watcher-agent 只记录会话级元数据:

  • code agent 名称,例如 pi
  • 项目目录/项目名
  • 通过 ActivityWatch heartbeat 记录的 session 时长
  • 当前/最终使用的模型
  • 总 token 用量和费用
  • 多模型 session 中按模型拆分的 token/cost 明细

不会记录:

  • prompt 文本
  • assistant 回复文本
  • 工具调用参数/结果
  • 文件内容

Components

This repository ships two parts:

  1. Rust daemon (aw-watcher-agent)

    • Receives HTTP session events from code-agent integrations.
    • Writes merged live activity heartbeats to aw-watcher-agent-event_<hostname>.
    • Writes per-session completed/abandoned summaries to aw-watcher-agent-sum_<hostname>.
  2. pi extension (.pi/extensions/aw-watcher.ts)

    • Hooks into pi session/model/agent lifecycle events.
    • Sends session start/update/heartbeat/end events to the daemon.

组件

本仓库包含两部分:

  1. Rust daemon (aw-watcher-agent)

    • 接收来自 code agent 集成的 HTTP session 事件。
    • 将合并后的实时活动 heartbeat 写入 aw-watcher-agent-event_<hostname>
    • 将单个 session 的 completed/abandoned 汇总写入 aw-watcher-agent-sum_<hostname>
  2. pi 扩展 (.pi/extensions/aw-watcher.ts)

    • 监听 pi 的 session/model/agent 生命周期事件。
    • 向 daemon 发送 session start/update/heartbeat/end 事件。

ActivityWatch data model

The daemon writes two ActivityWatch buckets:

aw-watcher-agent-event_<hostname>  type=app.editor.activity
aw-watcher-agent-sum_<hostname>    type=app.code-agent.summary

The event bucket contains merged live activity. If multiple agent sessions are active at the same time, they are represented as one heartbeat event:

{
  "status": "active",
  "language": "code-agent",
  "project": "multiple",
  "file": "multiple",
  "active_session_count": 2,
  "code_agents": ["pi", "codex"],
  "projects": ["aw-watcher-agent", "virt"],
  "project_dirs": ["/path/to/aw-watcher-agent", "/path/to/virt"],
  "sessions": [
    {
      "code_agent": "pi",
      "session_id": "pi-72aa7acf",
      "project": "aw-watcher-agent",
      "project_dir": "/path/to/aw-watcher-agent",
      "model": "deepseek-v4-pro"
    }
  ]
}

The sum bucket contains one event per session active period. Its ActivityWatch event timestamp is the start of the active period, duration is the active duration in seconds, and data contains session metadata and completion state. Completed summaries also contain the final usage reported by the session end event:

{
  "status": "completed",
  "session_id": "pi-72aa7acf",
  "code_agent": "pi",
  "project": "aw-watcher-agent",
  "project_dir": "/path/to/aw-watcher-agent",
  "model": "deepseek-v4-pro",
  "active_duration_seconds": 42.5,
  "wall_duration_seconds": 80.2,
  "tokens_input": 24364,
  "tokens_output": 95,
  "tokens_cache_read": 5120,
  "tokens_cache_write": 0,
  "tokens_total": 29579,
  "cost_total": 0.02621523,
  "cost_currency": "USD",
  "model_usage": {
    "deepseek-v4-flash": {
      "tokens_input": 8050,
      "tokens_output": 39,
      "tokens_cache_read": 2560,
      "tokens_cache_write": 0,
      "tokens_total": 10649,
      "cost": 0.0012096
    },
    "deepseek-v4-pro": {
      "tokens_input": 8073,
      "tokens_output": 42,
      "tokens_cache_read": 2560,
      "tokens_cache_write": 0,
      "tokens_total": 10675,
      "cost": 0.01456438
    }
  }
}

Sessions that were active but timed out before an end event are written to the sum bucket with "status": "abandoned" and "reason": "timeout". Because no end event was received, abandoned summaries do not try to reconstruct token or cost usage.

ActivityWatch 数据模型

daemon 写入两个 ActivityWatch bucket:

aw-watcher-agent-event_<hostname>  type=app.editor.activity
aw-watcher-agent-sum_<hostname>    type=app.code-agent.summary

event bucket 记录合并后的实时活动;如果多个 agent session 同时活跃,会被合成 一条 heartbeat:

{
  "status": "active",
  "language": "code-agent",
  "project": "multiple",
  "file": "multiple",
  "active_session_count": 2,
  "code_agents": ["pi", "codex"],
  "projects": ["aw-watcher-agent", "virt"],
  "project_dirs": ["/path/to/aw-watcher-agent", "/path/to/virt"],
  "sessions": [
    {
      "code_agent": "pi",
      "session_id": "pi-72aa7acf",
      "project": "aw-watcher-agent",
      "project_dir": "/path/to/aw-watcher-agent",
      "model": "deepseek-v4-pro"
    }
  ]
}

sum bucket 每条 event 对应一个 session 活跃期。ActivityWatch event 的 timestamp 是活跃期开始时间,duration 是活跃秒数,data 包含 session 元数据和完成状态。completed summary 还会包含 session end 事件上报的最终 usage:

{
  "status": "completed",
  "session_id": "pi-72aa7acf",
  "code_agent": "pi",
  "project": "aw-watcher-agent",
  "project_dir": "/path/to/aw-watcher-agent",
  "model": "deepseek-v4-pro",
  "active_duration_seconds": 42.5,
  "wall_duration_seconds": 80.2,
  "tokens_input": 24364,
  "tokens_output": 95,
  "tokens_cache_read": 5120,
  "tokens_cache_write": 0,
  "tokens_total": 29579,
  "cost_total": 0.02621523,
  "cost_currency": "USD",
  "model_usage": {
    "deepseek-v4-flash": {
      "tokens_input": 8050,
      "tokens_output": 39,
      "tokens_cache_read": 2560,
      "tokens_cache_write": 0,
      "tokens_total": 10649,
      "cost": 0.0012096
    },
    "deepseek-v4-pro": {
      "tokens_input": 8073,
      "tokens_output": 42,
      "tokens_cache_read": 2560,
      "tokens_cache_write": 0,
      "tokens_total": 10675,
      "cost": 0.01456438
    }
  }
}

活跃过但超时前没有收到 end 事件的 session 会以 "status": "abandoned""reason": "timeout" 写入 sum bucket。由于没有收到 end 事件,abandoned summary 不会尝试重建 token 或费用用量。


Installation

Rust daemon

Download the binary from GitHub Releases, or build from source:

cargo build --release

Then place the binary on your PATH:

install -Dm755 target/release/aw-watcher-agent ~/.local/bin/aw-watcher-agent

pi extension

The npm package contains only the pi extension and package metadata.

pi install @wind_mask/aw-watcher-agent-pi

Alternatively, load the extension file directly while developing:

pi --extension .pi/extensions/aw-watcher.ts

安装

Rust daemon

可以从 GitHub Releases 下载二进制文件,也可以从源码构建:

cargo build --release

然后将二进制放入 PATH

install -Dm755 target/release/aw-watcher-agent ~/.local/bin/aw-watcher-agent

pi 扩展

npm 包只包含 pi 扩展和 package 元数据。

pi install @wind_mask/aw-watcher-agent-pi

开发时也可以直接加载扩展文件:

pi --extension .pi/extensions/aw-watcher.ts

Usage

Start ActivityWatch first, then run the daemon:

aw-watcher-agent daemon

By default, the daemon:

  • connects to ActivityWatch at localhost:5600
  • listens for pi extension events on 127.0.0.1:5667

Check daemon status:

aw-watcher-agent status

Remove the ActivityWatch buckets created by this watcher:

aw-watcher-agent teardown

Environment variables

The pi extension sends events to:

http://127.0.0.1:5667

Override it with:

export AW_WATCHER_DAEMON_URL=http://127.0.0.1:5667

Agent heartbeat interval while pi is generating a response defaults to 15 seconds. The minimum effective value is 5 seconds:

export AW_WATCHER_AGENT_HEARTBEAT_INTERVAL_MS=15000

The daemon connects to ActivityWatch using CLI options:

aw-watcher-agent --host localhost --port 5600 daemon

使用

先启动 ActivityWatch,然后运行 daemon:

aw-watcher-agent daemon

默认情况下,daemon 会:

  • 连接到 localhost:5600 上的 ActivityWatch
  • 127.0.0.1:5667 监听 pi 扩展事件

检查 daemon 状态:

aw-watcher-agent status

删除本 watcher 创建的 ActivityWatch buckets:

aw-watcher-agent teardown

环境变量

pi 扩展默认将事件发送到:

http://127.0.0.1:5667

可以通过环境变量覆盖:

export AW_WATCHER_DAEMON_URL=http://127.0.0.1:5667

agent 生成回复期间的 heartbeat 间隔默认为 15 秒;有效最小值为 5 秒:

export AW_WATCHER_AGENT_HEARTBEAT_INTERVAL_MS=15000

daemon 连接 ActivityWatch 的地址通过 CLI 选项配置:

aw-watcher-agent --host localhost --port 5600 daemon

Resume behavior

When a pi session is resumed, the extension records only usage produced after the resume point. Existing historical messages in the resumed session file are not counted again.

Resume 行为

当 pi session 被 resume 时,扩展只记录 resume 之后新增的用量。resume 前已经存在于 session 文件中的历史消息不会被重复计入。


Migrating legacy data

Versions before the dual-bucket data model wrote everything to the legacy aw-watcher-agent_<hostname> bucket. To backfill existing exports into the new aw-watcher-agent-event_<hostname> and aw-watcher-agent-sum_<hostname> buckets, export the old bucket from ActivityWatch and run:

python3 scripts/migrate_legacy_aw_bucket.py aw-bucket-export_aw-watcher-agent_<hostname>.json --output migrated-aw-watcher-agent.json

The command above is a dry run and writes a converted export file. After reviewing the printed counts, import directly into a running ActivityWatch server with:

python3 scripts/migrate_legacy_aw_bucket.py aw-bucket-export_aw-watcher-agent_<hostname>.json --apply

Use --skip-event-bucket to migrate only completed/abandoned summaries, or --skip-abandoned to avoid creating abandoned summaries for sessions that never sent an end event.

迁移旧数据

双 bucket 数据模型之前的版本会把所有数据写入旧的 aw-watcher-agent_<hostname> bucket。要把已有导出回填到新的 aw-watcher-agent-event_<hostname>aw-watcher-agent-sum_<hostname> buckets,先从 ActivityWatch 导出旧 bucket,然后运行:

python3 scripts/migrate_legacy_aw_bucket.py aw-bucket-export_aw-watcher-agent_<hostname>.json --output migrated-aw-watcher-agent.json

上面的命令是 dry run,并会写出转换后的 export 文件。确认输出统计无误后,可以 直接导入到正在运行的 ActivityWatch:

python3 scripts/migrate_legacy_aw_bucket.py aw-bucket-export_aw-watcher-agent_<hostname>.json --apply

如果只想迁移 completed/abandoned 汇总,可加 --skip-event-bucket;如果不想为 没有 end 事件的 session 创建 abandoned summary,可加 --skip-abandoned


License

MIT

许可证

MIT