-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Hi, thanks for building cops — really excited about having observability for Claude Code sessions.
After a fresh install of v0.1.1 on macOS (Apple Silicon), I completed all the setup steps (Google OAuth, cops add, daemon running via LaunchAgent), but the dashboard at cops.team-attention.com shows 0 tokens, 0 sessions, 0 projects.
I spent some time debugging and traced through the source code to understand what might be going wrong. Sharing my findings below in case they're helpful.
1. cops add doesn't set organizationId in global config
When I run cops add, the project-level config (<project>/.cops/config.json) gets the correct organizationId, but the global config (~/.cops/config.json) ends up with organizationId: "".
What I found in the source:
In cli/internal/service/tracking/tracking_service.go, the AddProject() method saves the local config with params.OrganizationID correctly:
localConfig := &config.LocalConfig{
ProjectID: projectID,
OrganizationID: params.OrganizationID, // ✓ set here
}
s.configRepo.SaveLocalConfig(projectPath, localConfig)But when constructing the domain.Project for the global config, OrganizationID isn't assigned:
project := &domain.Project{
ProjectAbstract: domain.ProjectAbstract{
ID: projectID,
Name: name,
Path: projectPath,
},
IsGitProject: isGitProject,
RegisteredAt: time.Now(),
// OrganizationID not set → Go zero value ""
}The field exists on the struct (shared/domain/project.go), it's just not populated during construction.
To reproduce:
cops add /path/to/project
cat ~/.cops/config.json # → organizationId: ""
cat /path/to/project/.cops/config.json # → organizationId: "abc123..." (correct)2. Daemon doesn't appear to send data to the API server
I noticed the daemon process is running and reading JSONL files (SQLite file_positions are being updated), but there are no outgoing network connections:
lsof -p $(pgrep cops-daemon) | grep -i "tcp\|ssl\|https"
# → (no results)The API server itself is reachable (curl returns 404 at root, which is expected).
What I found in the source:
Looking at daemon/internal/platform/interceptor/auth_interceptor.go, when GetAccessToken() returns an error, the interceptor returns CodeUnauthenticated without calling next() — so the HTTP request is never made:
token, err := i.authState.GetAccessToken(ctx)
if err != nil {
return nil, connect.NewError(connect.CodeUnauthenticated, err)
}In daemon/internal/service/logwatcher/log_service.go, when send fails, returnLinesToBuffer() puts unsent lines back in memory. But since SQLite file positions were already advanced (in the fsnotify handler, before flush), those lines would be lost if the daemon restarts.
The daemon logs only show startup messages — no send/flush/batch related output — which is consistent with requests being blocked at the interceptor level.
3. Initial scan on daemon startup seems to run before watch targets are ready
Every time the daemon starts, I see this in the logs:
loaded file positions count=0
log fsnotify handler started
no watched directories, skipping initial scan ← scan happens here
fsnotify handlers started
all handlers started
updated watch targets watching=326 ← targets arrive here
What I found in the source:
In daemon/cmd/internal/container/register_fsnotify.go, the startup sequence is:
- SubscriberHandler (
LogPubsubHandler) — starts a goroutine listening on a pubsub channel - PublisherHandler (
ConfigWatcherFsnotifyHandler) — publishes watch targets to the buffered channel - FsnotifyHandler (
LogFsnotifyHandler) — callsscanExistingFiles()which checkswatcher.WatchList()
Since the pubsub consumer goroutine from step 1 may not have processed the message from step 2 by the time step 3 checks the watch list, WatchList() returns empty and the scan is skipped.
I tried clearing the file_positions table in SQLite and restarting, but since the scan itself is skipped, it didn't help.
Environment
| Item | Value |
|---|---|
| cops version | v0.1.1 |
| OS | macOS 15 (Apple Silicon) |
| Daemon | LaunchAgent |
| Auth | Google OAuth completed, ~/.cops/auth.json present |
Workaround I'm using
Manually editing ~/.cops/config.json to add the correct organizationId (copied from the project-level config). This addresses issue 1, though issues 2 and 3 may still apply.
Happy to provide more details or test anything if that would help. Thanks for your time!