@team-agent/installer 0.5.118 → 0.5.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/README.md +46 -1
- package/README.zh.md +46 -1
- package/crates/team-agent/src/cli/adapters.rs +11 -0
- package/crates/team-agent/src/cli/arguments.rs +401 -0
- package/crates/team-agent/src/cli/emit.rs +241 -142
- package/crates/team-agent/src/cli/intent/runtime.rs +1139 -0
- package/crates/team-agent/src/cli/intent/runtime_tests.rs +584 -0
- package/crates/team-agent/src/cli/intent/tests.rs +654 -0
- package/crates/team-agent/src/cli/intent.rs +642 -0
- package/crates/team-agent/src/cli/mod.rs +49 -5
- package/crates/team-agent/src/cli/named_address.rs +10 -1
- package/crates/team-agent/src/cli/spec.rs +22 -10
- package/crates/team-agent/src/cli/status_port/brief.rs +117 -16
- package/crates/team-agent/src/cli/tests/base.rs +6 -1
- package/crates/team-agent/src/cli/tests/parser_safety.rs +383 -0
- package/crates/team-agent/src/cli/tests/run_delegation.rs +63 -19
- package/crates/team-agent/src/cli/tests/verb_install_skill.rs +3 -2
- package/crates/team-agent/src/cli/tests/verb_profile.rs +3 -1
- package/crates/team-agent/src/contract_runtime/backend.rs +1 -1
- package/crates/team-agent/src/db/message_store.rs +10 -3
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +166 -77
- package/crates/team-agent/src/lifecycle/launch.rs +28 -0
- package/crates/team-agent/src/lifecycle/restart.rs +17 -0
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -3
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +5 -15
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -3
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +2 -3
- package/crates/team-agent/src/lifecycle/tests/cli_argv_routing_red.rs +10 -2
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +8 -1
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +6 -9
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +7 -5
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +4 -2
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +5 -2
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +4 -3
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +2 -4
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +3 -4
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +5 -4
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +2 -4
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +78 -36
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +8 -4
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +6 -12
- package/crates/team-agent/src/lifecycle/tests/pi_fork_session_inheritance_red.rs +4 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1 -3
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +7 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -3
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -1
- package/crates/team-agent/src/lifecycle/types.rs +10 -0
- package/crates/team-agent/src/messaging/delivery.rs +132 -39
- package/crates/team-agent/src/messaging/delivery_consumption_tests.rs +223 -0
- package/crates/team-agent/src/messaging/enter_rescue.rs +182 -154
- package/crates/team-agent/src/messaging/enter_rescue_tests.rs +344 -277
- package/crates/team-agent/src/messaging/mod.rs +1 -1
- package/crates/team-agent/src/tmux_backend/enter_rescue.rs +325 -0
- package/crates/team-agent/src/tmux_backend/enter_rescue_tests.rs +432 -0
- package/crates/team-agent/src/tmux_backend/native_input.rs +19 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +37 -0
- package/crates/team-agent/src/tmux_backend.rs +35 -1
- package/crates/team-agent/src/transport/enter_rescue.rs +166 -0
- package/crates/team-agent/src/transport/native_input.rs +5 -1
- package/crates/team-agent/src/transport/test_support.rs +25 -0
- package/crates/team-agent/src/transport.rs +34 -0
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +71 -54
- package/skills/team-agent/command-coverage.json +283 -13
- package/skills/team-agent/docs/reference/team-agent-operator.md +220 -0
- package/skills/team-agent/references/bug-as-artifact-flow.md +1 -1
- package/skills/team-agent/references/recovery-runbook.md +61 -212
- package/skills/team-agent/references/team-agent-operator.md +181 -48
- package/skills/team-agent/references/team-in-team.md +47 -80
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
//! Independent watchdog receipts. Registration is unconditional; key authority is not.
|
|
2
|
+
|
|
3
|
+
use serde::{Deserialize, Serialize};
|
|
4
|
+
use sha2::{Digest, Sha256};
|
|
5
|
+
|
|
6
|
+
use crate::model::enums::Provider;
|
|
7
|
+
|
|
8
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
9
|
+
pub struct EnterRescueContext {
|
|
10
|
+
pub message_id: String,
|
|
11
|
+
pub owner_team_id: String,
|
|
12
|
+
pub recipient: String,
|
|
13
|
+
pub payload_sha256: String,
|
|
14
|
+
pub target: Option<EnterRescueTarget>,
|
|
15
|
+
pub proof: Option<EnterRescueProof>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl EnterRescueContext {
|
|
19
|
+
pub fn marker(&self) -> String {
|
|
20
|
+
format!("[team-agent-token:{}]", self.message_id)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Binds an opaque-paste receipt to this message and this original carrier.
|
|
24
|
+
pub fn scope_sha256(&self) -> Option<String> {
|
|
25
|
+
let bytes = serde_json::to_vec(&(
|
|
26
|
+
&self.message_id,
|
|
27
|
+
&self.owner_team_id,
|
|
28
|
+
&self.recipient,
|
|
29
|
+
&self.payload_sha256,
|
|
30
|
+
&self.target,
|
|
31
|
+
))
|
|
32
|
+
.ok()?;
|
|
33
|
+
Some(format!("{:x}", Sha256::digest(bytes)))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn valid_proof(&self) -> bool {
|
|
37
|
+
self.proof.as_ref().is_some_and(|proof| {
|
|
38
|
+
proof.valid()
|
|
39
|
+
&& proof.owned_capsule.as_ref().is_none_or(|capsule| {
|
|
40
|
+
capsule.valid() && self.scope_sha256().as_ref() == Some(&capsule.scope_sha256)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub fn valid_message(&self) -> bool {
|
|
46
|
+
self.message_id.starts_with("msg_")
|
|
47
|
+
&& self
|
|
48
|
+
.message_id
|
|
49
|
+
.bytes()
|
|
50
|
+
.all(|b| b.is_ascii_alphanumeric() || b == b'_')
|
|
51
|
+
&& !self.owner_team_id.is_empty()
|
|
52
|
+
&& !self.recipient.is_empty()
|
|
53
|
+
&& self.recipient != "leader"
|
|
54
|
+
&& valid_digest(&self.payload_sha256)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// `selected` records canonical original routing, not a late adoption of a pane.
|
|
59
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
60
|
+
pub struct EnterRescueTarget {
|
|
61
|
+
pub provider: Provider,
|
|
62
|
+
pub endpoint: String,
|
|
63
|
+
pub pane_id: String,
|
|
64
|
+
pub pane_pid: u32,
|
|
65
|
+
pub pane_height: u32,
|
|
66
|
+
pub carrier_birth: String,
|
|
67
|
+
pub binding_nonce: String,
|
|
68
|
+
pub session: String,
|
|
69
|
+
pub window: String,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
impl EnterRescueTarget {
|
|
73
|
+
pub fn selected(
|
|
74
|
+
provider: Provider,
|
|
75
|
+
pane_id: String,
|
|
76
|
+
pane_pid: u32,
|
|
77
|
+
session: String,
|
|
78
|
+
window: String,
|
|
79
|
+
) -> Self {
|
|
80
|
+
Self {
|
|
81
|
+
provider,
|
|
82
|
+
pane_id,
|
|
83
|
+
pane_pid,
|
|
84
|
+
session,
|
|
85
|
+
window,
|
|
86
|
+
endpoint: String::new(),
|
|
87
|
+
pane_height: 0,
|
|
88
|
+
carrier_birth: String::new(),
|
|
89
|
+
binding_nonce: String::new(),
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
pub fn same_selection(&self, other: &Self) -> bool {
|
|
94
|
+
self.provider == other.provider
|
|
95
|
+
&& self.pane_id == other.pane_id
|
|
96
|
+
&& self.pane_pid == other.pane_pid
|
|
97
|
+
&& self.session == other.session
|
|
98
|
+
&& self.window == other.window
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub fn bound(&self) -> bool {
|
|
102
|
+
std::path::Path::new(&self.endpoint).is_absolute()
|
|
103
|
+
&& self.pane_id.starts_with('%')
|
|
104
|
+
&& self.pane_pid > 1
|
|
105
|
+
&& self.pane_height >= 10
|
|
106
|
+
&& !self.carrier_birth.is_empty()
|
|
107
|
+
&& !self.binding_nonce.is_empty()
|
|
108
|
+
&& !self.session.is_empty()
|
|
109
|
+
&& !self.window.is_empty()
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
114
|
+
pub struct EnterRescueProof {
|
|
115
|
+
pub ui_identity: String,
|
|
116
|
+
pub footer_sha256: String,
|
|
117
|
+
pub visible_marker: bool,
|
|
118
|
+
pub transcript_marker_absent: bool,
|
|
119
|
+
pub owned_capsule: Option<OwnedCapsule>,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
impl EnterRescueProof {
|
|
123
|
+
pub fn valid(&self) -> bool {
|
|
124
|
+
!self.ui_identity.is_empty()
|
|
125
|
+
&& valid_digest(&self.footer_sha256)
|
|
126
|
+
&& (self.visible_marker || self.owned_capsule.as_ref().is_some_and(OwnedCapsule::valid))
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Only a prior empty-baseline/single-owned-paste transition may create this.
|
|
131
|
+
/// Snapshotting a visible capsule label alone never creates ownership.
|
|
132
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
133
|
+
pub struct OwnedCapsule {
|
|
134
|
+
pub scope_sha256: String,
|
|
135
|
+
pub label: String,
|
|
136
|
+
pub baseline_sha256: String,
|
|
137
|
+
pub baseline_capsules: Vec<String>,
|
|
138
|
+
pub observed_after_owned_paste: bool,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
impl OwnedCapsule {
|
|
142
|
+
pub fn valid(&self) -> bool {
|
|
143
|
+
self.observed_after_owned_paste
|
|
144
|
+
&& valid_digest(&self.scope_sha256)
|
|
145
|
+
&& !self.label.is_empty()
|
|
146
|
+
&& self.label.len() <= 80
|
|
147
|
+
&& valid_digest(&self.baseline_sha256)
|
|
148
|
+
&& !self.baseline_capsules.contains(&self.label)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
fn valid_digest(value: &str) -> bool {
|
|
153
|
+
value.len() == 64 && value.bytes().all(|b| b.is_ascii_hexdigit())
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
157
|
+
pub enum EnterRescueOutcome {
|
|
158
|
+
Consumed,
|
|
159
|
+
NoEffect {
|
|
160
|
+
reason: &'static str,
|
|
161
|
+
reobserve: bool,
|
|
162
|
+
},
|
|
163
|
+
Entered {
|
|
164
|
+
accepted: bool,
|
|
165
|
+
},
|
|
166
|
+
}
|
|
@@ -131,7 +131,7 @@ pub(crate) fn record_evidence(evidence: &NativeInputEvidence) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
134
|
-
pub
|
|
134
|
+
pub struct InputFrame {
|
|
135
135
|
pub composer: String,
|
|
136
136
|
pub transcript: String,
|
|
137
137
|
pub identity: String,
|
|
@@ -195,6 +195,10 @@ fn input_digest(text: &str) -> String {
|
|
|
195
195
|
format!("{:x}", Sha256::digest(text.as_bytes()))
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
pub(crate) fn supports_input_observation(provider: Provider) -> bool {
|
|
199
|
+
matches!(provider, Provider::Pi | Provider::CursorAgent)
|
|
200
|
+
}
|
|
201
|
+
|
|
198
202
|
pub(crate) fn inspect_input(
|
|
199
203
|
provider: Provider,
|
|
200
204
|
text: &str,
|
|
@@ -57,6 +57,8 @@ struct OfflineState {
|
|
|
57
57
|
/// answer keyed by pane id. Used by leader provider health tests.
|
|
58
58
|
pane_current_commands: BTreeMap<String, String>,
|
|
59
59
|
session_owner: Option<super::SessionOwner>,
|
|
60
|
+
native_input_observation: Option<super::native_input::InputFrame>,
|
|
61
|
+
native_input_error: Option<String>,
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
impl Default for OfflineState {
|
|
@@ -85,6 +87,8 @@ impl Default for OfflineState {
|
|
|
85
87
|
capture_ranges: Vec::new(),
|
|
86
88
|
pane_current_commands: BTreeMap::new(),
|
|
87
89
|
session_owner: None,
|
|
90
|
+
native_input_observation: None,
|
|
91
|
+
native_input_error: None,
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
}
|
|
@@ -95,6 +99,16 @@ pub struct OfflineTransport {
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
impl OfflineTransport {
|
|
102
|
+
pub fn with_native_input_observation(self, frame: super::native_input::InputFrame) -> Self {
|
|
103
|
+
self.with_state(|state| state.native_input_observation = Some(frame));
|
|
104
|
+
self
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
pub fn with_native_input_error(self, reason: &str) -> Self {
|
|
108
|
+
self.with_state(|state| state.native_input_error = Some(reason.into()));
|
|
109
|
+
self
|
|
110
|
+
}
|
|
111
|
+
|
|
98
112
|
pub fn new() -> Self {
|
|
99
113
|
Self::default()
|
|
100
114
|
}
|
|
@@ -434,6 +448,17 @@ impl OfflineTransport {
|
|
|
434
448
|
}
|
|
435
449
|
|
|
436
450
|
impl Transport for OfflineTransport {
|
|
451
|
+
fn observe_native_input(
|
|
452
|
+
&self,
|
|
453
|
+
_target: &Target,
|
|
454
|
+
_provider: crate::model::enums::Provider,
|
|
455
|
+
) -> Result<Option<super::native_input::InputFrame>, TransportError> {
|
|
456
|
+
self.with_state(|state| match &state.native_input_error {
|
|
457
|
+
Some(reason) => Err(TransportError::NativeInputNotReady { reason: reason.clone() }),
|
|
458
|
+
None => Ok(state.native_input_observation.clone()),
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
|
|
437
462
|
fn kind(&self) -> BackendKind {
|
|
438
463
|
BackendKind::Tmux
|
|
439
464
|
}
|
|
@@ -67,6 +67,7 @@ use std::path::{Path, PathBuf};
|
|
|
67
67
|
use serde::{Deserialize, Serialize};
|
|
68
68
|
use thiserror::Error;
|
|
69
69
|
|
|
70
|
+
pub mod enter_rescue;
|
|
70
71
|
pub mod native_input;
|
|
71
72
|
|
|
72
73
|
#[cfg(test)]
|
|
@@ -989,6 +990,39 @@ pub trait Transport: Send + Sync {
|
|
|
989
990
|
Ok(report)
|
|
990
991
|
}
|
|
991
992
|
|
|
993
|
+
/// Observation only; None means this backend/provider has no native parser.
|
|
994
|
+
/// An implemented parser with an incomplete frame returns an error, not absence.
|
|
995
|
+
fn observe_native_input(
|
|
996
|
+
&self,
|
|
997
|
+
_target: &Target,
|
|
998
|
+
_provider: crate::model::enums::Provider,
|
|
999
|
+
) -> Result<Option<native_input::InputFrame>, TransportError> {
|
|
1000
|
+
Ok(None)
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/// Snapshot the original attempted target without submitting or adopting a capsule.
|
|
1004
|
+
fn snapshot_enter_rescue(
|
|
1005
|
+
&self,
|
|
1006
|
+
_target: &Target,
|
|
1007
|
+
context: &enter_rescue::EnterRescueContext,
|
|
1008
|
+
_rendered_payload: &str,
|
|
1009
|
+
) -> Result<enter_rescue::EnterRescueContext, TransportError> {
|
|
1010
|
+
Ok(context.clone())
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/// Independent delayed Enter-only watchdog, not native-input admission.
|
|
1014
|
+
fn rescue_enter_guarded(
|
|
1015
|
+
&self,
|
|
1016
|
+
_context: &enter_rescue::EnterRescueContext,
|
|
1017
|
+
_authorize: &dyn Fn() -> bool,
|
|
1018
|
+
_observer: Option<&dyn SubmitObserver>,
|
|
1019
|
+
) -> Result<enter_rescue::EnterRescueOutcome, TransportError> {
|
|
1020
|
+
Ok(enter_rescue::EnterRescueOutcome::NoEffect {
|
|
1021
|
+
reason: "unsupported_backend",
|
|
1022
|
+
reobserve: false,
|
|
1023
|
+
})
|
|
1024
|
+
}
|
|
1025
|
+
|
|
992
1026
|
/// Enter-only recovery; unsupported backends have an explicit zero-effect refusal.
|
|
993
1027
|
fn rescue_enter(&self, _evidence: &native_input::NativeInputEvidence, _authorize: &dyn Fn() -> bool, _observer: Option<&dyn SubmitObserver>)
|
|
994
1028
|
-> Result<native_input::EnterRescueOutcome, TransportError>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-agent/installer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.120",
|
|
4
4
|
"description": "npx installer for Team Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"team-agent-installer": "npm/install.mjs"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@team-agent/cli-darwin-arm64": "0.5.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.5.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.5.
|
|
23
|
+
"@team-agent/cli-darwin-arm64": "0.5.120",
|
|
24
|
+
"@team-agent/cli-darwin-x64": "0.5.120",
|
|
25
|
+
"@team-agent/cli-linux-x64": "0.5.120"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postinstall": "node npm/bincheck.mjs",
|
|
@@ -5,27 +5,30 @@ requires_team_agent: ">=0.5.0"
|
|
|
5
5
|
---
|
|
6
6
|
# Team Agent
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Use the authorized **Leader's** native tool context for lifecycle operations. Workers report through their team-scoped MCP tools; loading this skill does not promote a worker to Leader. Operate in the workspace root, not inside another team's role directory.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Check the actual CLI
|
|
11
|
+
|
|
12
|
+
Check `team-agent --version`, `team-agent start --help` and `team-agent team --help` before using this guide. It requires the intuitive `start`, `stop`, `team` and `agent` surface. A version string or this skill's compatibility floor is not proof those commands exist. If missing, ask for an authorized installation of a supporting build; do not silently switch binaries, rewrite bindings or fall back to an old creation recipe.
|
|
13
|
+
|
|
14
|
+
## User decisions come first
|
|
11
15
|
|
|
12
16
|
**The user decides each worker's provider and permission bypass. Do not silently choose Pi, true, or false.** Reuse an explicit user policy when it covers the worker; otherwise explain the choices and ask before starting.
|
|
13
17
|
|
|
14
|
-
Use existing resources rather than establishing
|
|
18
|
+
Use existing resources rather than establishing accounts. `team-agent doctor --workspace . --json` reports discovered tools; installed is not authenticated, and an unknown probe is not proof of unavailability. Use `team-agent models --provider NAME` where supported for exact model IDs. Do not inspect credentials, automatically log in, or silently substitute providers.
|
|
15
19
|
|
|
16
|
-
| Choice |
|
|
20
|
+
| Choice | Explain |
|
|
17
21
|
|---|---|
|
|
18
|
-
| Pi |
|
|
19
|
-
| Codex | The user's existing
|
|
20
|
-
|
|
|
21
|
-
| Bypass `
|
|
22
|
-
| Bypass `false` | Keep the selected tool's native permissions; human confirmation may interrupt unattended work |
|
|
22
|
+
| Pi | Several model catalogs; an explicit model needs a qualified ID such as `openai-codex/gpt-6-luna` |
|
|
23
|
+
| Codex / Claude / other native CLIs | The user's existing workflow, native permissions, model catalog and supported session capabilities |
|
|
24
|
+
| Bypass `true` | Fewer interruptions, broader automatic authority |
|
|
25
|
+
| Bypass `false` | Native permissions remain; human confirmation may interrupt unattended work |
|
|
23
26
|
|
|
24
|
-
False is **not** a read-only or sandbox guarantee.
|
|
27
|
+
False is **not** a read-only or sandbox guarantee. Different workers may use different providers; an existing worker cannot change provider. Do not invent a model or effort when the user left it unset.
|
|
25
28
|
|
|
26
|
-
##
|
|
29
|
+
## Prepare once, start every day
|
|
27
30
|
|
|
28
|
-
Keep the goal in `TEAM.md` and each worker's instructions in `agents/*.md`. The filename stem is the worker's in-team short name
|
|
31
|
+
Keep the goal in `TEAM.md` and each worker's instructions in `agents/*.md`. The filename stem is the worker's in-team short name:
|
|
29
32
|
|
|
30
33
|
```text
|
|
31
34
|
.team/current/
|
|
@@ -33,7 +36,7 @@ Keep the goal in `TEAM.md` and each worker's instructions in `agents/*.md`. The
|
|
|
33
36
|
agents/reviewer.md
|
|
34
37
|
```
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
Record provider and boolean bypass in every new role. This example assumes the user explicitly chose Pi and bypass false; it is not a default:
|
|
37
40
|
|
|
38
41
|
```markdown
|
|
39
42
|
---
|
|
@@ -43,43 +46,58 @@ dangerously_skip_permissions: false
|
|
|
43
46
|
Review the change and report concrete regression risks.
|
|
44
47
|
```
|
|
45
48
|
|
|
49
|
+
From the authorized Leader context, select the intended workspace/team:
|
|
50
|
+
|
|
46
51
|
```sh
|
|
47
|
-
team-agent
|
|
48
|
-
team-agent
|
|
49
|
-
team-agent
|
|
52
|
+
team-agent start --from .team/current --workspace . --team project-team
|
|
53
|
+
team-agent start --workspace . --team project-team
|
|
54
|
+
team-agent send reviewer "Review this change" --workspace . --team project-team
|
|
55
|
+
team-agent inbox leader --workspace . --team project-team -n 3
|
|
50
56
|
```
|
|
51
57
|
|
|
52
|
-
|
|
58
|
+
The first `start` creates a complete configured team through the original creation path. Later `start` keeps physically verified, drift-free live seats unchanged and starts stopped non-paused seats, including explicitly stopped seats. It is not a reset. Missing configuration, ambiguous scope or unknown physical identity is a refusal, not permission to overwrite state. `--dry-run` plans without lifecycle effects; final locked admission is still deferred.
|
|
59
|
+
|
|
60
|
+
Accepted/queued send is **not** the worker's answer. Wait for a natural reply/result. `ok: true` with pending readiness is not business readiness. A live no-op does not synchronize edited role bodies or apply changed launch settings.
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
## Stop, wake and restart
|
|
55
63
|
|
|
56
64
|
```sh
|
|
57
|
-
|
|
58
|
-
team-agent
|
|
59
|
-
|
|
60
|
-
team-agent
|
|
65
|
+
team-agent stop reviewer --workspace . --team project-team
|
|
66
|
+
team-agent start reviewer --workspace . --team project-team
|
|
67
|
+
team-agent restart reviewer --workspace . --team project-team
|
|
68
|
+
team-agent stop --workspace . --team project-team --json
|
|
69
|
+
team-agent start --workspace . --team project-team
|
|
70
|
+
team-agent team restart --workspace . --team project-team --json
|
|
61
71
|
```
|
|
62
72
|
|
|
63
|
-
|
|
73
|
+
| Intent | Rule |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `start AGENT` | Wake a stopped registered seat; verified live/no-drift is a no-op. A RoleOnly seat can be added from its complete role file |
|
|
76
|
+
| `start` | Explicitly activate the selected non-paused roster; do not use it unless that activation is authorized |
|
|
77
|
+
| `stop AGENT` / `stop` | Retain saved session associations; whole-team stop also checks scoped residual resources |
|
|
78
|
+
| `restart AGENT` / `team restart` | Default `--session auto`: resume when proven, otherwise only the original legal fresh fallback. **Auto does not guarantee preserved memory** |
|
|
79
|
+
| `--session preserve` | Require available continuation evidence; refuse before stopping when continuation is known unavailable |
|
|
80
|
+
|
|
81
|
+
Team restart preserves explicitly stopped and paused seats; use `start` when intentionally waking the roster. Paused seats are not implicitly unpaused. A same-named directory makes `restart ID` ambiguous: use `agent restart ID`. `reviewer.v2` remains an agent ID; choose a team source with `--from DIR`, `team start DIR` or an explicit path such as `./roles`.
|
|
82
|
+
|
|
83
|
+
For strict recovery, prefer `team-agent team restart --session preserve --workspace . --team project-team`. Do not convert a refusal or partial/unknown replacement into reset, force or blind retry. Inspect `status`/`doctor` in the same scope first. Native unsupported capabilities remain refusals, never a legacy fallback.
|
|
64
84
|
|
|
65
|
-
##
|
|
85
|
+
## Add or change one worker
|
|
66
86
|
|
|
67
|
-
|
|
87
|
+
With the user's provider/bypass choices, `start` unifies adding an absent seat and waking an existing one:
|
|
68
88
|
|
|
69
89
|
```sh
|
|
70
|
-
team-agent
|
|
71
|
-
team-agent start
|
|
72
|
-
team-agent stop
|
|
73
|
-
team-agent start
|
|
90
|
+
team-agent start auditor --role-file /absolute/path/to/auditor.md
|
|
91
|
+
team-agent start analyst --provider pi --bypass false --prompt "Analyze the proposed change"
|
|
92
|
+
team-agent stop reviewer
|
|
93
|
+
team-agent start reviewer --effort high --bypass false
|
|
74
94
|
```
|
|
75
95
|
|
|
76
|
-
|
|
96
|
+
The Pi/false example above still requires the user's explicit choices. File/CLI conflicts are rejected before writing or startup. Omitted settings/body are preserved; `--prompt` replaces the permanent role body, not a one-time task. Stop a running worker before changing settings or instructions. Provider changes are refused. Startup failure restores role/spec bytes and reports failure, not an applied update.
|
|
77
97
|
|
|
78
|
-
|
|
98
|
+
Use `agent add/remove/reset/clone/fork` only for those explicit operations. Reset needs intentional approval and `--discard-session`; fork requires `--as NEW_ID`, and `--in-place` is not supported. See [the operator reference](references/team-agent-operator.md) for capability, profile, force and import boundaries. Never put secrets in role text or copy authentication from another directory.
|
|
79
99
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
## Global native CLI argv (optional)
|
|
100
|
+
## Optional native CLI argv routing
|
|
83
101
|
|
|
84
102
|
Default OFF; no workspace or provider login is needed to manage routes:
|
|
85
103
|
|
|
@@ -93,29 +111,28 @@ team-agent route clear pi
|
|
|
93
111
|
team-agent route disable
|
|
94
112
|
```
|
|
95
113
|
|
|
96
|
-
`set` replaces one mapping, `add` appends without deduplication, `clear` removes it;
|
|
97
|
-
none changes the switch. `enable`/`disable` preserve mappings in `~/.team-agent/argv-routing.json`.
|
|
98
|
-
`TEAM_AGENT_CLI_ARGV_ROUTING` overrides the switch: `1/true/on`, `0/false/off` (case-insensitive,
|
|
99
|
-
trimmed); invalid values disable routing. Check `persisted_enabled`, `effective_enabled` and
|
|
100
|
-
`override_status` rather than assuming `enable` defeats an environment OFF.
|
|
114
|
+
`set` replaces one mapping, `add` appends without deduplication, `clear` removes it; none changes the switch. `enable`/`disable` preserve mappings in `~/.team-agent/argv-routing.json`. `TEAM_AGENT_CLI_ARGV_ROUTING` overrides the switch: `1/true/on`, `0/false/off` (case-insensitive, trimmed); invalid values disable routing. Check `persisted_enabled`, `effective_enabled` and `override_status`.
|
|
101
115
|
|
|
102
|
-
Keys: `claude`, `codex`, `copilot`, `gemini_cli`, `grok`, `cursor_agent`, `pi`.
|
|
103
|
-
Claude/Claude Code share `claude`; aliases `claude_code/claude-code`, `agent/cursor` are accepted.
|
|
104
|
-
The first `--` ends control parsing: subsequent tokens, including `--help`, `--json`, empty strings
|
|
105
|
-
and `{workspace}`, are literal data. Tokens go after the executable and before its original tail;
|
|
106
|
-
there is no shell expansion. Do not route secrets or override framework-managed session/MCP/permission flags.
|
|
116
|
+
Keys: `claude`, `codex`, `copilot`, `gemini_cli`, `grok`, `cursor_agent`, `pi`. Claude/Claude Code share `claude`; aliases `claude_code/claude-code`, `agent/cursor` are accepted. Everything after the first `--`, including `--help`, `--json`, empty strings and `{workspace}`, is literal argv. No shell expansion. Do not route secrets or override framework-managed session/MCP/permission flags.
|
|
107
117
|
|
|
108
|
-
|
|
109
|
-
add/clone, Pi new-seat fork and remove rollback), not running/attached processes, dry-run or helper probes.
|
|
110
|
-
Enabled bad configuration prevents native spawn; an emergency environment OFF avoids reading it,
|
|
111
|
-
while `route disable` will not overwrite a broken file. Pi `--mode rpc` does not provide an RPC host
|
|
112
|
-
or change the existing Team Agent transport.
|
|
118
|
+
Mappings affect the next actual native spawn, not running/attached processes, dry-run or helper probes. Invalid enabled configuration refuses spawn; an emergency environment OFF avoids reading it, while `route disable` will not overwrite a broken file. Pi `--mode rpc` does not provide an RPC host or replace Team Agent's transport.
|
|
113
119
|
|
|
114
|
-
##
|
|
120
|
+
## Observe, communicate and clean up
|
|
115
121
|
|
|
116
|
-
Use `team-agent status --json`
|
|
122
|
+
Use `team-agent status --json` (or `team status`) for the concise node projection and `doctor` for diagnosis; `--detail` does not restore old internal status dumps. Use `<workspace>::<team>/<agent>` for an explicitly qualified logical recipient, or the in-team short name. Workers have exactly `send_message`, `report_result` and optional `get_team_status`; lifecycle stays on the authorized CLI. Read [nested teams](references/team-in-team.md) only when explicitly requested and [recovery](references/recovery-runbook.md) for incidents.
|
|
117
123
|
|
|
118
|
-
|
|
124
|
+
Finish with `team-agent stop --workspace . --team project-team --json` when authorized. Check the actual scoped residual report; exit0 alone is not proof of zero resources. Do not kill shared servers or touch sibling workspaces.
|
|
119
125
|
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
## Compatibility bridges, not the daily workflow
|
|
127
|
+
|
|
128
|
+
Old commands remain available for existing scripts; their output/defaults are not silently rewritten:
|
|
129
|
+
|
|
130
|
+
| Compatibility entry | Preferred daily surface |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `quick-start` | `start --from TEAMDIR` for creation and later `start` for activation |
|
|
133
|
+
| `shutdown` | `stop` / `team stop` |
|
|
134
|
+
| `add-agent` / `start-agent` / `stop-agent` | `agent add` for strict add, or `start AGENT` / `stop AGENT` |
|
|
135
|
+
| `remove-agent` / `reset-agent` / `clone-agent` / `fork-agent` | The corresponding `agent` operation |
|
|
136
|
+
| Bare or explicit-path `restart` | Frozen preserve bridge; deliberate `team restart` defaults to auto |
|
|
137
|
+
|
|
138
|
+
These are not all byte-equivalent aliases: legacy single-seat start refuses a running seat, while new start can prove a no-op. Do not mechanically rename automation, assume unsupported provider capabilities, or infer deployment from package metadata.
|