Developer Handover Pack
Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.
Developer Handover Pack
New Tool Evaluation & Rollout
[YourCompany.com] · IT Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for the three-agent New Tool Evaluation and Rollout automation. It covers the current-state process map, full agent specifications with IO contracts, end-to-end data flow, and the recommended build stack. The FullSpec team uses this pack to build and test the automation from scratch. No external developer or third-party agency is involved. Where this document specifies field names, status values, or API behaviours, those specifications govern the build.
01Process snapshot
02Agent specifications
Receives the structured intake form submission, creates a Jira ticket with all captured request fields, queries the Notion software register for duplicate or overlapping tools, flags any match on the Jira ticket, and posts an acknowledgement message to the requestor in Slack. This agent eliminates the unstructured multi-channel request intake and the informal manual duplicate check. All intake data is normalised at this stage and carried forward as the canonical record for the evaluation.
// Input form.requestor_name : string form.requestor_email : string form.tool_name : string form.use_case : string form.user_count : integer form.budget_range : string form.integrations_needed : string[] form.submitted_at : ISO8601 timestamp // Output jira.ticket_id : string // e.g. IT-204 jira.ticket_status : string // 'Intake Received' jira.duplicate_flag : boolean // true if Notion match found jira.duplicate_tool_name : string // populated if duplicate_flag = true slack.ack_message_ts : string // Slack message timestamp for threading
- Jira tier required: Jira Software Cloud (Standard or above) to access the REST API v3. Project key must be confirmed before build (e.g. 'IT'). Issue type must be 'Task' or a custom 'Tool Request' type, confirmed with the IT Manager before field mapping.
- Notion duplicate check: query the 'Software Register' database using the tool_name field against the 'Tool Name' property. Use a contains filter, not an exact-match filter, to catch partial name overlaps. The Notion database ID must be captured during stack audit and stored as an environment variable (NOTION_SOFTWARE_REGISTER_DB_ID).
- If the Notion software register contains inconsistently formatted entries, the duplicate check will return false negatives. The register must be cleaned and standardised before this agent goes live. This is a confirmed pre-build dependency.
- Slack acknowledgement must be sent to the requestor's Slack user ID, resolved from form.requestor_email via the Slack users.lookupByEmail API method. If no Slack account is found for that email, fall back to posting to a designated #it-requests channel and tagging the email address in the message body.
- Deduplication: if duplicate_flag is true, the Jira ticket is created and flagged but the workflow does not proceed to the Evaluation and Approval Agent automatically. IT Manager reviews and closes the ticket manually (retained human decision point).
- The intake form must include all fields listed in the Input block above. Any optional fields must still be submitted as empty strings to prevent null-handling errors downstream.
Triggered when the Jira ticket status transitions to 'Evaluation In Progress', this agent generates a pre-built security checklist and a standardised evaluation scorecard in Notion, both pre-populated with the request details from the Jira ticket. It monitors Notion for checklist and scorecard completion, then sends a formatted approval request email via Google Workspace to the designated approver. If no response is recorded within 48 hours, a follow-up reminder is queued automatically. The agent continues queuing reminders until a decision is recorded in Jira, at which point it closes the approval loop.
// Input jira.ticket_id : string jira.tool_name : string jira.requestor_name : string jira.requestor_email : string jira.use_case : string jira.user_count : integer jira.budget_range : string jira.integrations_needed : string[] // Output (on scorecard + checklist creation) notion.security_checklist_page_id : string notion.scorecard_page_id : string notion.checklist_status : string // 'Pending' | 'Complete' notion.scorecard_status : string // 'Pending' | 'Complete' // Output (on approval request sent) gmail.approval_email_message_id : string gmail.reminder_scheduled_at : ISO8601 timestamp jira.ticket_status : string // 'Pending Approval' // On approval jira.approval_decision : string // 'Approved' | 'Rejected' jira.decision_recorded_at : ISO8601 timestamp jira.approver_name : string jira.ticket_status : string // 'Approved' | 'Rejected'
- Notion templates: the security checklist and evaluation scorecard must be created as Notion template pages before build begins. The agent duplicates these templates into the relevant evaluation database and populates properties from the Jira ticket fields. Template page IDs must be stored as environment variables (NOTION_SECURITY_CHECKLIST_TEMPLATE_ID, NOTION_SCORECARD_TEMPLATE_ID).
- Approval email: sent via the Gmail API (users.messages.send) using a service account with domain-wide delegation, or via an authenticated IT Manager OAuth2 token. The email must include the Notion scorecard URL, tool name, requestor name, and a clear approval/rejection reply instruction or a linked form.
- Reminder logic: implement a scheduled polling job (every 24 hours) that checks whether the Jira ticket status is still 'Pending Approval'. If true and 48 hours have elapsed since gmail.approval_email_message_id was recorded, send a reminder. Cap reminders at three before escalating to a Slack alert in #it-alerts.
- Approval capture: the approval decision must be recorded back into Jira via the REST API by updating the ticket status and adding a comment with approver_name and decision_recorded_at. The approval response mechanism (email reply parsing, linked form, or manual Jira update) must be confirmed with the IT Manager before build.
- The security checklist criteria must be reviewed by a stakeholder familiar with the business's compliance obligations before the template is finalised, particularly for regulated or high-risk tool categories. This is a pre-build dependency and cannot be resolved by FullSpec unilaterally.
- Google Workspace tier: the Gmail API requires a Google Workspace account with API access enabled. OAuth2 scopes required: gmail.send, gmail.readonly (for reply monitoring if used). Confirm API access and service account configuration during stack audit.
Triggered when the Jira ticket status transitions to 'Approved', this agent sends a DocuSign envelope containing the vendor agreement or internal purchase order to the required signatories. Once the envelope is completed, the agent updates the Notion software register with the new tool entry including licence count, renewal date, owner, and monthly cost. It then sends a Slack notification to the requestor and any named users confirming the tool is live and linking to onboarding materials. If the approval decision is 'Rejected', the agent records the outcome in Jira and notifies the requestor via Slack without triggering DocuSign.
// Input jira.ticket_id : string jira.approval_decision : string // 'Approved' | 'Rejected' jira.tool_name : string jira.requestor_name : string jira.requestor_email : string jira.user_count : integer jira.budget_range : string jira.approver_name : string jira.decision_recorded_at : ISO8601 timestamp // On approval: DocuSign output docusign.envelope_id : string docusign.envelope_status : string // 'sent' | 'completed' | 'declined' docusign.signed_at : ISO8601 timestamp // On signature completed: Notion output notion.register_page_id : string // new entry in Software Register notion.tool_name : string notion.licence_count : integer notion.renewal_date : date notion.owner : string notion.monthly_cost_usd : number notion.status : string // 'Active' // Output: Slack notification slack.rollout_message_ts : string slack.channel_or_user : string
- DocuSign: the vendor agreement template must be pre-loaded in DocuSign and the correct signatory roles mapped (e.g. 'Vendor Signer', 'IT Manager', 'Finance Controller') before this agent can be built. The template ID must be stored as an environment variable (DOCUSIGN_TEMPLATE_ID). A one-off setup step per agreement type is required. This is a confirmed pre-build dependency.
- DocuSign tier: DocuSign Personal or Standard plan is sufficient for this volume. The eSignature REST API v2.1 is used. Authentication via JWT grant (recommended for server-to-server) or Authorization Code grant. Account ID and integration key must be provisioned and stored securely.
- If the approval decision is 'Rejected', skip all DocuSign logic. Update the Jira ticket status to 'Rejected', add a comment with the approver name and timestamp, and send a Slack direct message to the requestor notifying them of the outcome. Do not post rejection details publicly in a shared channel.
- Notion register update: triggered by the DocuSign 'envelope completed' webhook event, not on envelope send. The agent must listen for the docusign.envelope_status = 'completed' event before writing to Notion. Map licence_count, renewal_date, owner, and monthly_cost_usd from the Jira ticket fields or prompt IT to populate these on the ticket before the workflow proceeds.
- Slack rollout notification: resolve the requestor's Slack user ID via users.lookupByEmail. If the Jira ticket contains additional named users (a multi-user field), resolve each and send individual DMs or a single message in a relevant channel. Include the tool name, a confirmation that access is being provisioned, and a link to the onboarding materials page in Notion.
- Fallback on DocuSign decline: if docusign.envelope_status = 'declined', update the Jira ticket to 'Procurement Stalled', alert the IT Manager via Slack DM, and halt the workflow. Do not auto-retry without human review.
03End-to-end data flow
// ============================================================
// TRIGGER
// ============================================================
// Event: Google Workspace intake form submitted
// Webhook payload received by orchestration layer
TRIGGER {
form.requestor_name = 'string'
form.requestor_email = 'string'
form.tool_name = 'string'
form.use_case = 'string'
form.user_count = integer
form.budget_range = 'string'
form.integrations_needed = ['string', ...]
form.submitted_at = ISO8601
}
// ============================================================
// AGENT 1: Request Intake Agent
// ============================================================
// Step 1a: Create Jira ticket
POST /rest/api/3/issue {
project.key -> env: JIRA_PROJECT_KEY
issuetype -> 'Task' or 'Tool Request'
summary -> form.tool_name + ' - Tool Request'
description -> form.use_case
customfield_requestor_name -> form.requestor_name
customfield_requestor_email -> form.requestor_email
customfield_user_count -> form.user_count
customfield_budget_range -> form.budget_range
customfield_integrations -> form.integrations_needed
status -> 'Intake Received'
}
RETURNS: jira.ticket_id // e.g. 'IT-204'
// Step 1b: Query Notion software register for duplicate
POST /v1/databases/{NOTION_SOFTWARE_REGISTER_DB_ID}/query {
filter: { property: 'Tool Name', rich_text: { contains: form.tool_name } }
}
IF results.length > 0:
jira.duplicate_flag = true
jira.duplicate_tool_name = results[0].properties['Tool Name'].title
// Update Jira ticket with duplicate flag; halt agent handoff
// IT Manager reviews and closes ticket manually
ELSE:
jira.duplicate_flag = false
// Proceed to agent handoff
// Step 1c: Acknowledge requestor via Slack
GET /api/users.lookupByEmail?email={form.requestor_email}
-> slack.user_id (fallback: post to #it-requests if not found)
POST /api/chat.postMessage {
channel -> slack.user_id
text -> 'Your request for {form.tool_name} has been received. Ticket: {jira.ticket_id}'
}
RETURNS: slack.ack_message_ts
// ============================================================
// AGENT 1 -> AGENT 2 HANDOFF
// Condition: jira.duplicate_flag = false
// Trigger: Jira ticket status updated to 'Evaluation In Progress'
// ============================================================
// ============================================================
// AGENT 2: Evaluation and Approval Agent
// ============================================================
// Step 2a: Duplicate Notion security checklist template
POST /v1/pages {
parent.database_id -> env: NOTION_SECURITY_CHECKLIST_DB_ID
properties: {
'Tool Name' -> jira.tool_name
'Ticket ID' -> jira.ticket_id
'Status' -> 'Pending'
'Assigned To' -> 'IT Manager'
}
// Content cloned from NOTION_SECURITY_CHECKLIST_TEMPLATE_ID
}
RETURNS: notion.security_checklist_page_id
// Step 2b: Duplicate Notion scorecard template
POST /v1/pages {
parent.database_id -> env: NOTION_SCORECARD_DB_ID
properties: {
'Tool Name' -> jira.tool_name
'Ticket ID' -> jira.ticket_id
'Use Case' -> jira.use_case
'User Count' -> jira.user_count
'Budget Range' -> jira.budget_range
'Integrations' -> jira.integrations_needed
'Scorecard Status' -> 'Pending'
}
}
RETURNS: notion.scorecard_page_id
// Step 2c: Poll Notion for checklist and scorecard completion
// Scheduled check every 6 hours
GET /v1/pages/{notion.security_checklist_page_id}
-> notion.checklist_status // watch for 'Complete'
GET /v1/pages/{notion.scorecard_page_id}
-> notion.scorecard_status // watch for 'Complete'
// Step 2d: Send approval request email once both statuses = 'Complete'
POST /gmail/v1/users/me/messages/send {
to -> approver_email // resolved from APPROVER_EMAIL env var
subject -> 'Approval required: {jira.tool_name} evaluation'
body -> evaluation summary + notion.scorecard_page_id URL
}
RETURNS: gmail.approval_email_message_id
SET: gmail.reminder_scheduled_at = now() + 48h
UPDATE: jira.ticket_status -> 'Pending Approval'
// Step 2e: Reminder logic (scheduled poller every 24h)
IF jira.ticket_status = 'Pending Approval'
AND now() > gmail.reminder_scheduled_at:
// Send reminder email (up to 3 times)
// On 3rd miss: POST Slack alert to #it-alerts
// Step 2f: Capture approval decision
// Via Jira ticket status update (manual by approver or form response)
ON jira.ticket_status IN ('Approved', 'Rejected'):
jira.approval_decision = ticket.status
jira.decision_recorded_at = now()
jira.approver_name = ticket.updated_by.displayName
// ============================================================
// AGENT 2 -> AGENT 3 HANDOFF
// Trigger: Jira ticket status transitions to 'Approved' or 'Rejected'
// ============================================================
// ============================================================
// AGENT 3: Procurement and Rollout Agent
// ============================================================
// Branch A: Approval decision = 'Rejected'
IF jira.approval_decision = 'Rejected':
UPDATE jira.ticket_status -> 'Rejected'
POST /api/chat.postMessage to requestor slack.user_id
text -> 'Your request for {jira.tool_name} was not approved.'
HALT
// Branch B: Approval decision = 'Approved'
// Step 3a: Send DocuSign envelope
POST /v2.1/accounts/{DOCUSIGN_ACCOUNT_ID}/envelopes {
templateId -> env: DOCUSIGN_TEMPLATE_ID
templateRoles: [
{ roleName: 'IT Manager', email: IT_MANAGER_EMAIL, name: IT_MANAGER_NAME }
{ roleName: 'Finance Controller', email: FINANCE_EMAIL, name: FINANCE_NAME }
]
status: 'sent'
}
RETURNS: docusign.envelope_id
// Step 3b: Listen for DocuSign envelope webhook event
ON docusign.envelope_status = 'completed':
docusign.signed_at = envelope.completedDateTime
// Step 3c: Update Notion software register
POST /v1/pages {
parent.database_id -> env: NOTION_SOFTWARE_REGISTER_DB_ID
properties: {
'Tool Name' -> jira.tool_name
'Status' -> 'Active'
'Licence Count' -> jira.user_count
'Owner' -> jira.requestor_name
'Monthly Cost' -> parsed from jira.budget_range
'Renewal Date' -> signed_at + 12 months
'Ticket ID' -> jira.ticket_id
}
}
RETURNS: notion.register_page_id
// Step 3d: Send Slack rollout notification
POST /api/chat.postMessage {
channel -> slack.user_id (requestor)
text -> '{jira.tool_name} is approved and being provisioned.
Onboarding materials: {notion.scorecard_page_id URL}'
}
RETURNS: slack.rollout_message_ts
ON docusign.envelope_status = 'declined':
UPDATE jira.ticket_status -> 'Procurement Stalled'
POST Slack alert to IT Manager DM
HALT
// ============================================================
// END OF FLOW
// ============================================================04Recommended build stack
More documents for this process
Every document generated for New Tool Evaluation & Rollout.