* refactor(cli): migrate to Cobra-based command structure
Refactor CLI to use Cobra instead of manual os.Args parsing.
- Introduce root command and structured subcommands under cmd/picoclaw/internal
- Convert agent, auth, cron, gateway, migrate, onboard, skills, status and version to Cobra commands
- Replace manual flag parsing with Cobra flags
- Remove direct os.Args usage from command handlers
- Keep existing command behavior and output semantics
This change focuses on CLI structure and maintainability.
No business logic changes intended.
* chore(cli): remove version2 alias and make cobra a direct dependency
* test(cli): add basic command tests
- Add tests for CLI command tree and flag parsing
- Align LDFLAGS injection path for version info
- Remove unused manual help function
* test: migrate command tests to testify assertions
Replace standard library testing error checks (t.Error*, t.Fatalf)
with assert/require from stretchr/testify across all cobra command tests
for improved readability and consistency.
* fix(cli): make linter happy
* test: avoid duplication in windows config path test
* test: simplify allowed command checks using slices.Contains
* fix(skills): register subcommands during command construction
- Move subcommand registration out of PersistentPreRunE
- Ensure `picoclaw skills <subcommand>` resolves correctly
- Minor install command and test cleanups
* refactor(cli): address review feedback and improve command clarity
* fix(authLogoutCmd): rm os.Exit
The configuration field for specifying the model has been renamed from
"model" to "model_name" for better clarity and consistency with the
model_list configuration.
A GetModelName() accessor method has been added to maintain backward
compatibility. Existing configurations using the old "model" field will
continue to work correctly.
This change affects:
- Configuration structure (AgentDefaults struct)
- All references across the codebase
- Documentation in all language variants
- Example configuration files
When users migrate from the legacy `providers` config to the new
`model_list` format, voice transcription silently breaks on Telegram,
Discord and Slack channels.
The gateway was reading the Groq API key exclusively from
`cfg.Providers.Groq.APIKey`, which is empty once the key is defined
only inside a `model_list` entry. The transcriber was never initialized,
so voice messages fell back to a plain `[voice]` placeholder.
This fix also scans `model_list` for any entry whose `model` field
starts with `groq/` and uses its `api_key` as a fallback, preserving
full backward compatibility with the legacy `providers.groq` field.
Address review comment from @xiaket - the "Supported providers" message
was printed in multiple places. Now extracted as a constant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all claude-sonnet-4 references with claude-sonnet-4.6 across
codebase including documentation, tests, and configuration examples.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auth fixes:
- Fix OpenAI/Anthropic OAuth and token login to update ModelList
- Fix logout to clear AuthMethod in ModelList
- Add helper functions: isOpenAIModel, isAnthropicModel, isAntigravityModel
- Fix slice bounds panic in isAntigravityModel using strings.HasPrefix
- All auth operations now preserve existing model_list configuration
Factory provider fixes:
- Add OAuth support for openai protocol in CreateProviderFromConfig
- CodexAuthProvider is now used when auth_method is oauth/token
Default model updates:
- OpenAI login: set default model to gpt-5.2
- Anthropic login: set default model to claude-sonnet-4
- Antigravity login: set default model to gemini-flash (remove provider field)
Model changes:
- Change default OpenAI model from gpt-4o to gpt-5.2
- gpt-5.2 is compatible with Codex API (chatgpt.com backend)
- Update all README files, config examples, and migration code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Include all 17 supported providers in default config as templates
- Each entry has model_name, model, api_base, and empty api_key
- Add comments with API key links for each provider
- Keep onboard message simple (only OpenRouter and Ollama)
- Fix duplicate model_name (cerebras-llama-3.3-70b)
Providers included:
Zhipu, OpenAI, Anthropic, DeepSeek, Gemini, Qwen, Moonshot,
Groq, OpenRouter, NVIDIA, Cerebras, Volcengine, ShengsuanYun,
Antigravity, GitHub Copilot, Ollama, VLLM
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move provider creation logic to factory_provider.go with protocol-based approach
- Add OpenAIProviderConfig with WebSearch support and embedded ProviderConfig
- Add maxTokensField to OpenAI-compatible provider for configurable token field
- Introduce new providers: Ollama, DeepSeek, GitHubCopilot, Antigravity, Qwen
- Remove redundant CreateProvider function from factory.go
- Add ThoughtSignature field to FunctionCall for tool response handling
- Remove duplicate Name field assignment in tool loop
- Update tests to reflect new provider configuration structure
Refactor command handlers into separate files to improve code organization
and maintainability. Each command (agent, auth, cron, gateway, migrate,
onboard, skills, status) now has its own dedicated file.
Restructure provider creation to support new model_list configuration
system that enables zero-code addition of OpenAI-compatible providers.
Move legacy provider logic to separate file for backward compatibility.
Move configuration functions from config.go to separate files
(defaults.go, migration.go) for better organization.
- write config and cron store with 0600 instead of 0644
- check allow list in Slack slash commands and app mentions
- pass workspace restrict flag to cron exec tool
Closes#179
Add a new configuration option `exec_timeout_minutes` under the `tools.cron`
section to control the maximum execution time for cron jobs. The default
timeout is set to 5 minutes, which is appropriate for LLM operations.
The configuration can be set in the config file or via the
`PICOCLAW_TOOLS_CRON_EXEC_TIMEOUT_MINUTES` environment variable. A value of
0 disables the timeout entirely.
This change improves system reliability by preventing cron jobs from running
indefinitely in case of unexpected failures or hanging processes.
Extract formatVersion() and formatBuildInfo() helper functions to reduce code duplication between printVersion() and statusCmd(). Update git commit default value to "dev" in Makefile for consistency with version handling. Update documentation for QQ and DingTalk chat integration in Japanese README.
Extract core LLM tool loop logic into shared RunToolLoop function that can be
used by both main agent and subagents. Subagents now run their own tool loop
with dedicated tool registry, enabling full independence.
Key changes:
- New pkg/tools/toolloop.go with reusable tool execution logic
- Subagents use message tool to communicate directly with users
- Heartbeat processing is now stateless via ProcessHeartbeat
- Simplified system message routing without result forwarding
- Shared tool registry creation for consistency between agents
This architecture follows openclaw's design where async tools notify via
bus and subagents handle their own user communication.
feat(config): add heartbeat interval configuration with default 30 minutes
feat(state): migrate state file from workspace root to state directory
feat(channels): skip internal channels in outbound dispatcher
feat(agent): record last active channel for heartbeat context
refactor(subagent): use configurable default model instead of provider default
- Remove redundant ChannelSender interface, use *bus.MessageBus directly
- Consolidate two handlers (onHeartbeat, onHeartbeatWithTools) into one
- Move HEARTBEAT.md and heartbeat.log to workspace root
- Simplify NewHeartbeatService signature (remove handler param)
- Add SetBus and SetHandler methods for dependency injection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-enable cronTool service integration after completing the ToolResult
refactor (US-016). Removed all temporary disable comments and restored
full cron service lifecycle including start/stop operations.
Additional improvements:
- Add thread-safe access to onHeartbeatWithTools handler
- Fix channel parsing to handle user IDs with special characters
- Add error handling for state file loading failures
Resolved conflicts:
- pkg/heartbeat/service.go: merged both 'started' field and 'onHeartbeatWithTools'
- pkg/tools/edit.go: use validatePath() with ToolResult return
- pkg/tools/filesystem.go: fixed return values to use ToolResult
- cmd/picoclaw/main.go: kept active setupCronTool, fixed toolsPkg import
- pkg/tools/cron.go: fixed Execute return value handling
Fixed tests for new function signatures (NewEditFileTool, NewAppendFileTool, NewExecTool)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added HeartbeatConfig struct with Enabled field
- Added Heartbeat to Config struct
- Set default Heartbeat.Enabled = true in DefaultConfig()
- Updated main.go to use cfg.Heartbeat.Enabled instead of hardcoded true
- Added config tests verifying heartbeat is enabled by default
Acceptance criteria met:
- DefaultConfig() Heartbeat.Enabled changed to true
- Can override via PICOCLAW_HEARTBEAT_ENABLED=false env var
- Config documentation updated showing default enabled
- Typecheck passes (go build ./... succeeds)
- go test ./pkg/config -run TestDefaultConfig passes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>