Synchronize work activities across Harvest, Linear, and Slack - featuring automated daily standups, AI-powered time tracking, and comprehensive activity reporting.
- Natural Language Time Entry: Tell Claude "I worked on the API for 2 hours" and it's logged
- Smart Prompts System: Guided workflows for time tracking
- Context-Aware Suggestions: Claude helps you track time based on your patterns
- Voice-Like Interaction: No more clicking through forms - just describe your work
- Daily Posts: Automatically posts standup updates at 9 AM (configurable)
- Harvest Integration: Fetches all time entries from the previous day
- Linear Integration: Shows completed issues and work in progress
- Smart Formatting: Project codes like [GC], [API] for easy scanning
- Duplicate Detection: Avoids showing Linear issues already in Harvest
- TypeScript Support: Full type safety for the MCP server
- Docker Ready: Production-grade containerization
- Timezone Aware: Works across global teams
- Test Modes: Dry runs and immediate testing
- Modular Architecture: Use components independently
**What have you done since yesterday?**
β’ [AKC] Created a comprehensive task list and testing plan for the correlation feature
β’ [AKC] Started development of the correlation feature
β’ [GC] Good Code: Meeting: Internal
β’ [LIN] Completed ENG-123: Fix authentication bug
β’ [API] Worked on API-456: Implement rate limiting
**What will you do today?**
β’ [ENG] Work on ENG-789: Refactor user service
β’ [API] Work on API-012: Add pagination to endpoints
β’ [LIN] Work on LIN-345: Update documentation
**Anything blocking your progress? Any vacation/etc coming up?**
Partial block on testing API responses due to the lack of access to the .env file
- Node.js 20+ (for local development)
- Docker & Docker Compose (for containerized deployment)
- Harvest account with API access
- Linear account with API access (optional)
- Slack workspace with webhook permissions
# If using git
git clone https://github.com/yourusername/worksync.git
cd worksync
# Or create the directory
mkdir -p ~/worksync
cd ~/worksync- Log in to Harvest
- Click on your profile β "Developers"
- Create a new Personal Access Token
- Copy the token and your Account ID
- Go to https://api.slack.com/apps
- Create a new app (or use existing)
- Go to "Incoming Webhooks" β Enable
- Add New Webhook to Workspace
- Select the channel for standup posts
- Copy the webhook URL
- Go to Linear β Settings β API
- Click "Personal API keys"
- Create a new key with a descriptive name
- Copy the generated key
Create a .env file in the project root:
# Harvest credentials
HARVEST_ACCOUNT_ID=your_account_id
HARVEST_ACCESS_TOKEN=your_harvest_token
# Slack webhook
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# Linear API (optional - leave empty to skip Linear integration)
LINEAR_API_KEY=lin_api_your_key_here
# Timezone (see: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
TIMEZONE=America/New_York# Build the Docker image
docker-compose build
# Test run to verify everything works
docker-compose run --rm standup-bot node index.js --test# Start the bot (runs in background)
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the bot
docker-compose down# Make script executable
chmod +x docker-run.sh
# Run the interactive menu
./docker-run.sh# Install dependencies
npm install
# Test run
npm run test-run# Start the bot
npm start
# Or use the helper script
chmod +x run-bot.sh
./run-bot.shThe bot runs daily at 9:00 AM in your configured timezone. To change the schedule, edit index.js:
// Change the cron expression (uses standard cron format)
cron.schedule('0 9 * * *', runDailyUpdate, {
timezone: TIMEZONE
});
// Examples:
// '30 8 * * *' - 8:30 AM daily
// '0 9 * * 1-5' - 9:00 AM Monday-Friday only
// '0 10 * * *' - 10:00 AM dailyCustomize how project names map to codes in index.js:
const projectMappings = {
'Good Code': 'GC',
'Engineering': 'ENG',
'API Team': 'API',
'Mobile App': 'MOB',
// Add your mappings here
};The bot automatically pulls your assigned Linear issues. To customize or add static plans, modify the getTodayPlans() function in index.js.
Currently returns "No blockers" by default. You can:
- Set an environment variable:
BLOCKERS="Your blocker message" - Modify the code to read from a file
- Integrate with your project management tool
# Deploy with production configuration
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# View logs
docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f- VPS/Cloud Server: Deploy to any Linux server with Docker
- Kubernetes: Use the Dockerfile to create a Kubernetes deployment
- Cloud Run/ECS: Deploy as a containerized service
- Local Server: Run on any always-on computer
The production configuration includes health checks. Monitor with:
# Check container health
docker ps
docker inspect worksync | grep -A 5 "Health"- Check console output - message is printed if webhook fails
- Verify webhook URL is correct and starts with
https://hooks.slack.com/services/ - Ensure the channel still exists and webhook has permissions
- Verify you have entries for yesterday in Harvest
- Check timezone settings - "yesterday" is timezone-dependent
- Run test mode to see what date is being queried
- Verify your API key is correct
- The bot continues without Linear data if connection fails
- Check if Linear API is accessible from your network
# Fix Docker permissions
sudo chown -R $(whoami):$(whoami) ~/.docker
# Or run with sudo
sudo docker-compose buildFor detailed debugging, add to your .env:
DEBUG=trueThen check logs for verbose output.
The MCP (Model Context Protocol) server allows Claude to add time entries to Harvest using natural language.
-
Install dependencies (including TypeScript):
npm install
-
Configure Claude Desktop:
Edit your Claude Desktop configuration file:
- Mac:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Add the Harvest MCP server:
{ "mcpServers": { "worksync-mcp": { "command": "npm", "args": ["run", "mcp"], "cwd": "/path/to/worksync", "env": { "HARVEST_ACCOUNT_ID": "1602879", "HARVEST_ACCESS_TOKEN": "your-harvest-token" } } } } - Mac:
-
Restart Claude Desktop to load the MCP server
Once configured, you can tell Claude things like:
- "Add meet with Austin for 30m"
- "Log 2 hours of development on the API project"
- "Add 45 minutes internal meeting yesterday"
- "Show me my time entries for the last week"
- "How many hours have I logged today?"
The MCP server now includes intelligent prompts that guide you through time tracking:
- discover - Start here! Shows all capabilities and examples
- guide - Get personalized suggestions based on your current tracking
- smart_add - Analyzes natural language to help you add complex entries
- weekly_review - Guides you through reviewing and filling time gaps
- quick_log - Fast shortcuts for common activities (meeting, lunch, break)
Example workflow:
You: "Use the discover prompt"
Claude: [Shows all capabilities and smart examples]
You: "Use the guide prompt"
Claude: [Analyzes your current hours and suggests what to track next]
You: "Use smart_add 'worked on the API documentation for 2.5 hours this morning'"
Claude: [Breaks down the interpretation and shows exact command to run]
You: "Use quick_log meeting"
Claude: [Sets up a 30-minute meeting entry]
Claude will use the MCP server to:
- Parse the duration (30m, 2h, 1.5 hours, etc.)
- Find the appropriate project and task
- Add the time entry to Harvest
- Show you confirmation of what was added
- add_time_entry: Add time with natural language
- list_recent_entries: Show recent time entries
- get_today_total: Get today's total hours
# Run MCP server in development mode with auto-reload
npm run dev:mcp
# Build TypeScript files
npm run buildworksync/
βββ index.js # Main application code
βββ mcp-server.ts # TypeScript MCP server for Claude
βββ package.json # Node.js dependencies
βββ tsconfig.json # TypeScript configuration
βββ .env # Your configuration (git ignored)
βββ .env.example # Example configuration
βββ Dockerfile # Docker container definition
βββ docker-compose.yml # Docker Compose configuration
βββ docker-compose.prod.yml # Production overrides
βββ docker-run.sh # Docker management script
βββ run-bot.sh # Local run helper script
βββ claude-mcp-config.json # Example MCP configuration
βββ README.md # This file
βββ .gitignore # Git ignore rules
βββ .dockerignore # Docker ignore rules
- Never commit
.envfiles - Keep credentials secure - Use environment variables in production instead of
.envfiles - Rotate API tokens regularly
- Limit webhook permissions to specific channels
- Run containers as non-root (already configured)
- Keep dependencies updated:
npm audit fix
Contributions are welcome! To contribute:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
# Install all dependencies (including dev)
npm install
# Run tests (if available)
npm test
# Check code style
npm run lintThis project is licensed under the MIT License - see the LICENSE file for details.
- Built with Node.js and the Linear SDK
- Uses Harvest API v2
- Integrates with Slack via Incoming Webhooks
- Scheduling powered by node-cron
For issues and questions:
- Check the troubleshooting section
- Review logs for error messages
- Create an issue in the repository
- Contact your system administrator
Made with β€οΈ to automate daily standups and keep teams in sync