{# Shared form fragments. #} {% macro err(errors, name) %} {%- if errors and name in errors %}{{ errors[name] }}{% endif -%} {% endmacro %} {% macro errors_box(errors) %} {%- if errors %}
Could not save:
{%- endif %} {% endmacro %} {% macro filter_control(col, active, form_id) %} {%- if col.kind == 'enum' -%} {%- else -%} {%- endif -%} {% endmacro %} {% macro sort_links(col, sort, dir, sort_url) %} ▲▼ {%- endmacro %} {% macro filter_help() %} ?what does !text mean? Filters (one box per column, combined with AND)
textcontains
!textdoes not contain
=textequals
>5 <5larger / smaller (numbers, dates as 2026-09-01, otherwise text order)
-empty
*not empty
Lists: cmd-click (ctrl-click) to select several. Sorting: ▲ A to Z, ▼ Z to A next to each heading; empty values sort last. Filters, sorting and search stay in the URL, so a view can be bookmarked.
{%- endmacro %} {% macro filter_form(form_id, action, active, q=None, sort='', dir='asc') %}
{% if q is not none %}{% endif %} {% if sort %}{% endif %} {{ filter_help() }} {% if active or sort %}clear filters and sorting{% endif %}
{% endmacro %} {% macro drafts_section(company, draft_contact, drafts, signal, observation, page) %}

Message drafts{% if draft_contact %} for {{ draft_contact.first_name }}{% endif %} ({{ language_names[drafts[0].language] }})

Three deliberately different angles, no AI. Square brackets are yours to fill. Edit in place, copy, or open it in the log form. The language is the contact's draft language, else the company's country; the picker here changes it for this page only.

{% for d in drafts %}
{{ d.label }}
log as sent
{% endfor %}
{% endmacro %} {# An interaction is always with a person. With `contact` (the contact page) the person is fixed; elsewhere you pick one. A note has no direction. #} {% macro interaction_form(action, company, values, errors=None, submit='Log interaction', contact=None) %}
{{ errors_box(errors) }}
{% for ch in channels %} {% endfor %} {% for d in directions %} {% endfor %} {% if contact %} {% else %} {% endif %}
{{ custom_fields(custom_fields_for('interaction'), values, errors) }} {# The body is the record. Custom fields sit beside it and never touch it. #}
{% endmacro %} {% macro custom_fields(defs, values, errors) %} {%- if defs %}
{% for f in defs %} {{ f.label }} {%- if f.type == 'select' %} {%- elif f.type == 'date' %} {%- elif f.type == 'number' %} {%- else %} {%- endif %} {{ err(errors, 'custom_' ~ f.key) }} {%- if f.help %} {{ f.help }}{% endif %} {% endfor %}
{%- endif %} {% endmacro %} {# `hide`: the fields layout.toml hides on the record page. A form leaves them out entirely, so saving keeps their values (web.submitted_only). #} {% macro company_fields(values, errors) %} {%- set hide = layout_hidden('company', errors) %}
{% if 'source' not in hide %}{% endif %}
{% if 'website' not in hide or 'linkedin' not in hide or 'country' not in hide %}
{% if 'website' not in hide %}{% endif %} {% if 'linkedin' not in hide %}{% endif %} {% if 'country' not in hide %}{% endif %}
{% endif %} {% if 'lost_reason' not in hide or 'requalify_on' not in hide or 'value_eur_month' not in hide %}
{% if 'lost_reason' not in hide %}{% endif %} {% if 'requalify_on' not in hide %}{% endif %} {% if 'value_eur_month' not in hide %}{% endif %}
{% endif %} {% if 'product_oneliner' not in hide %}
{% endif %} {{ custom_fields(custom_fields_for('company') | rejectattr('key', 'in', hide) | list, values, errors) }} {% if 'next_step' not in hide or 'next_step_due' not in hide or 'next_step_status' not in hide or (type_names() and 'next_step_type' not in hide) %}
{% if 'next_step' not in hide %}{% endif %} {% if 'next_step_due' not in hide %}{% endif %} {% if 'next_step_status' not in hide %}{% endif %} {% if type_names() and 'next_step_type' not in hide %}{% endif %}
{% endif %} {% if 'tags' not in hide %}{% endif %} {% if 'notes' not in hide %}{% endif %} {% endmacro %} {% macro contact_fields(values, errors) %} {%- set hide = layout_hidden('contact', errors) %}
{% if 'title' not in hide %}{% endif %} {% if 'role' not in hide %}{% endif %} {% set lang = (values.language or '') | trim | lower %} {% if 'language' not in hide %}{% endif %}
{% if 'email' not in hide or 'phone' not in hide or 'linkedin' not in hide %}
{% if 'email' not in hide %}{% endif %} {% if 'phone' not in hide %}{% endif %} {% if 'linkedin' not in hide %}{% endif %}
{% endif %} {{ custom_fields(custom_fields_for('contact') | rejectattr('key', 'in', hide) | list, values, errors) }} {% endmacro %} {% macro timeline(company, interactions) %} {% endmacro %} {% macro type_select(current='', autosubmit=false, name='type') -%} {%- set options = type_names() -%} {%- if options -%} {%- endif -%} {%- endmacro %} {% macro type_cell(company, t, index, contact='') -%} {% if type_names() and not t.done %}
{{ type_select(t.type, autosubmit=true) }}
{% else %}{{ type_chip(t.type) }}{% endif %} {%- endmacro %} {% macro type_chip(name) -%} {%- if name -%} {%- set colour = type_colour(name) -%} {{ name }} {%- endif -%} {%- endmacro %} {% macro todo_actions(company, todo, back='', delete=false) -%} {%- if todo.is_field -%}
{% if back %}{% endif %}
{%- if delete %}
{% if back %}{% endif %}
{%- endif %} {%- else -%}
{% if back %}{% endif %}
{%- if delete %}
{% if back %}{% endif %}
{%- endif %} {%- endif -%} {%- endmacro %} {% macro task_section(company, today) -%} {% set first = company.next_todo() %}

Tasks

For the company and its people. The next step is the open task due first; change a due date to change what is next. This company on the Tasks page.

{% if type_names() %}{% endif %} {% for t in company.open_todos() + (company.todos() | selectattr('done') | list) %} {% set is_next = first and not first.done and not t.done and t.key == first.key %} {% if type_names() %}{{ type_cell(company, t, t.index, t.contact.slug if t.contact else '') }}{% endif %} {% else %} {% endfor %}
tasktypeforduestatus
{{ t.text or '(no text)' }}{% if is_next %} next step{% endif %}{% if not type_names() %} {{ type_chip(t.type) }}{% endif %}{% if t.contact %}{{ t.contact.name }}{% else %}company{% endif %} {{ fmt_date(t.due) if t.due else 'no date' }} {% if t.done %}done{% if t.done_on %} {{ fmt_date(t.done_on) }}{% endif %}{% else %}open{% endif %} {{ todo_actions(company, t, delete=true) }} {% if is_next and t.due %}Add to Google Calendar{% endif %}
No tasks yet.
{% if type_names() %}{% endif %}
{%- endmacro %} {% macro task_list(company, tasks, today, contact='', adding=true) -%}
{% for t in tasks %} {% if type_names() %}{{ type_cell(company, t, loop.index0, contact) }}{% endif %} {% else %} {% endfor %}
{{ t.text }}{% if not type_names() %} {{ type_chip(t.type) }}{% endif %}{{ fmt_date(t.due) if t.due else '' }} {% if t.done %}done{% if t.done_on %} {{ fmt_date(t.done_on) }}{% endif %}{% endif %}
Nothing on the list.
{% if adding %}
{% if type_names() %}{% endif %}
{% endif %} {%- endmacro %} {# The handoff to the user's own agent (Make it yours): a request box and the buttons for the agent config.toml names. static/adjust.js builds the prompt, the link and the command from these data attributes as the user types, the same way adjust.handoff() does; the hint lines below say what each one does. #} {% macro handoff(h, id, page_title='', path='', label='Describe a change', text='', more=false) %}
{% if h.how == 'link' %}{{ h.button }}{% endif %} {% if h.how == 'command' %}{% endif %} {% if more %}More ideas{% endif %}
{% if h.how == 'link' %}{% endif %} {% if h.agent == 'claude' %}

Opens a terminal in your data folder with the request typed in. Nothing runs until you press Enter. Nothing opened? Run claude once in a terminal, then try again.

{% elif h.agent == 'cursor' %}

Open your data folder ({{ h.folder_shown }}) in Cursor first: the request goes to the Cursor window in front. Nothing runs until you press Enter.

{% elif h.how == 'command' %}

Paste the command in a terminal and press Enter: {{ h.label }} starts in your data folder with the request.

{% else %}

Paste the prompt into your AI agent, started in your data folder ({{ h.folder_shown }}). Name your agent to get a one-click button.

{% endif %}
What your agent receives

{% endmacro %}