Planned work, roughly in the order it is expected. Nothing here is a promise of a date; the issues hold the discussion of each item, and ideas are welcome there.
Since 1.50 (October 2026) only bug fixes and tests go in. The items below are collected for the time after it, in three waves: small things with immediate use first, then platform features, then the large projects.
| Item | Where |
|---|---|
| Trunk limits: calls per minute and channels (inbound and outbound together), health alarm Trunk limits | Trunks → Routing; Trunks |
| Voicemail limits and PIN rules | PBX settings → Voicemail; Voicemail |
| IVR menu repeat on no key; queue position and periodic announcements | IVR and queue forms |
| Spoken busy / no answer / unreachable messages (early media) | PBX settings → Ringtone |
| Night dialling protection | Dial permissions; Security |
All of them are off (or unchanged) until switched on.
| Item | Where |
|---|---|
| Scheduled tasks: sandboxed shell, PHP, Python background scripts | System → Scheduled tasks; Scheduled tasks |
| External database connections: encrypted MySQL/PostgreSQL storage & test | Integrations → Database connections; External databases |
| IVR data step: caller lookup via external DB or HTTP API | PBX → IVR Data Steps; IVR data steps |
| Carrier format & dialled number normalisation per trunk | Trunks → edit; Trunks |
| PBX fine tuning: per-trunk DTMF, session timers, 100rel, T.38, jitter buffer tuning, SIP timers, night restart, SIP debug | PBX settings → Tuning & Ops; PBX fine tuning, Trunks |
| Failed-registration threshold alarm (an Asterisk-side ACL is still open) | Health checks → Failed Registrations; Health checks, PBX tuning |
All of them are off (or unchanged) until switched on.
Still open from wave 2: the scheduled tasks’ data access (curated views in aipbx_export, a MariaDB
user per task, a REST API token per task, encrypted environment variables) — tasks run, but bring their
own credentials for now; number normalisation of dialled numbers by extensions (2.4, first point);
a failed-registration threshold inside Asterisk itself (2.6 has the alarm only). The sections below are
the full plan.
Goal. Administrators run their own shell, PHP or Python scripts on a schedule: nightly CDR export to an SFTP server, a CRM sync, a custom backup, polling a web service and raising an alert. Replaces the “plugin cron” idea of #118 with a feature for everyone.
Page (System → Scheduled tasks, administrators only, the whole feature off by default):
How it runs. One dispatcher started every minute (like the health checks) starts the due tasks.
Every run is a systemd-run sandbox: an unprivileged user aipbx-task (never root, never
www-data), read-only system, only the task’s own folder /var/lib/aipbx/tasks/<id>/ writable,
private /tmp, NoNewPrivileges, the limits above, no overlapping runs of the same task. Adding or
changing a task asks for the password again (and 2FA when on); every change and run is in the audit
log with the difference.
Data access.
aipbx_export, without any secret (SIP passwords, PINs,
password hashes, API keys, 2FA). Calls: calls, call_legs, missed_calls (call-back list),
calls_daily, call_quality, recordings. Call centre: queue_calls, agent_stats,
agent_pauses, queue_sla, cc_notes. PBX: extensions, extension_status, trunks, dids,
routes, ivrs, queues, ring_groups, time_conditions, conferences, phones. Fax:
fax_in, fax_out, fax_files. Voicemail: voicemail, voicemail_text. Chat: chat_stats,
chat_messages. System: health, alerts, audit, logins, sip_messages, ai_usage.
Views with personal data (recordings, notes, transcripts, chat messages, logins, file paths) need
an extra confirmation per task and every use is audited; their files are mounted read-only.
Administrators can save their own views as a SELECT over the allowed ones (checked on save).
Local time and UTC columns side by side.aipbx_tasks.AIPBX_DB_*
variables and a ready client file.Connections to MySQL / MariaDB and PostgreSQL (MSSQL and Oracle where the PHP drivers are installed), stored encrypted like plugin secrets, with a “test connection” button, a timeout and the advice to use a read-only account. Used by the IVR data step and by plugins.
A step in an IVR that runs a database query (2.2) or an HTTP request and puts the answer into a channel variable, with branches found, not found and timeout. Asterisk asks the portal on loopback; a hard limit of 2–3 seconds; HTTP requests go through the same guard as webhooks (no internal addresses). Example: “enter your customer number” → look up the customer → route VIP customers to their own queue.
A failed-registration threshold in Asterisk itself (next to Fail2ban), with the result in the health checks.
Goal. Provide a turnkey, zero-downtime container deployment for AiPBX without sacrificing telecommunications-grade performance or reliability.
Architecture: Decoupled Services vs. Monolithic “Fat Container”.
An all-in-one container running systemd, Asterisk, MariaDB, Web, Cron, and AI in a single image is deliberately rejected because:
aipbx-web restarts in seconds while aipbx-asterisk keeps running with zero interruption to ongoing calls.10000-20000/udp) through Docker proxy creates high jitter and latency. Decoupled Asterisk runs with network_mode: host for wire-speed media forwarding. ┌────────────────────────────────────────────────────────┐
│ HOST │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ aipbx-web │ │ aipbx-db │ │ aipbx-ai │ │
HTTP / HTTPS / API ──┼──>│ (PHP/Nginx) │──>│ (MariaDB) │ │ (Python) │ │
│ └──────┬───────┘ └──────────────┘ └────┬─────┘ │
│ │ Shared Volume / Unix Socket │ Audio │
│ ▼ ▼ Socket │
│ ┌────────────────────────────────────────────────┐ │
SIP / RTP (UDP) ─────┼──>│ aipbx-asterisk (Host Network: 5060 + 10k-20k) │ │
│ └────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
Services in the stack:
aipbx-asterisk: Realtime Asterisk engine with host networking (network_mode: host), zero-NAT overhead, and independent lifecycle.aipbx-web: PHP 8.2+ with Nginx, handling HTTP, WebSocket, and REST API calls. Can be updated and deployed independently.aipbx-db: Official MariaDB container with dedicated persistent named volumes (aipbx_db_data).aipbx-ai: Python FastAPI container housing Whisper STT, Kokoro/Piper TTS, and audio socket integrations.aipbx-signaling: Lightweight daemon capturing Homer/HEPv3 signaling packets.Goal. Enable cloud telecom providers to offer isolated, branded PBX instances to multiple business customers (tenants) from a centralized control plane.
Design Principles: Asterisk is a single-process engine; logical context partitioning alone is not safe against tenant-level crashes or transcoding CPU spikes. The enterprise cloud solution consists of:
tenant1.aipbx.bid, tenant2.aipbx.bid).A conference room per chat group (hidden number), started from the mobile app; membership is checked before joining; the group gets a “call started — join” message and a push notification, members join when they want (no ringing everyone).
Move ai-assistant out of the core into a community plugin, with a migration for installations that
use it.
The “nefes-0.5” voice (Hugging Face) as a remote engine for announcements; it needs an NVIDIA GPU with 16 GB, so it runs on a separate machine and AiPBX calls it like a cloud TTS.
Also waiting: per-domain apply of pending changes (#120).
| # | Item | Issue | Size |
|---|---|---|---|
| 1 | Website call widget and WordPress plugin | #14 | large |
| 2 | Delete chat messages and attachments | #15 | medium |
| 3 | S3 storage for chat attachments: done, see File storage | #15 | done |
| 4 | Video calls: web phone, Android, iOS and desk video phones done (1.22/1.50), see Video calls | #15 | done |
| 5 | Local AI models (EmbeddingGemma 2, EMA Lightning): steps 0–1 in Local AI models | large, in steps | |
| 6 | iOS app parity: same features as Android (swipe remove calls, notification reply, own message deletion, in-app image viewer) | done | |
| 7 | Dialplan pattern clean-up | small | |
| 8 | Busy lamps (BLF) and voicemail lamp on desk phones: watching 10–100 colleagues on multi-key phones | medium | |
| 9 | Phone provisioning page | large | |
| 10 | DHCP and TFTP management: first version in Network services | medium | |
| 11 | Visual IVR editor (later) | #16 | large |
| 12 | Server address change in one step: done (1.33.0), see Network settings | done | |
| 13 | Network settings page: done (1.33.0) except changing the server’s own address (netplan) | medium | |
| 14 | Menu reorganisation: done (1.33.0) | done |
Done recently: website call widget with the call-back form and a WordPress plugin (Website call widget); phone provisioning with key layouts (1.7.0, Phones); deleting chat messages and the _. dialplan clean-up (1.7.0); busy lamps on desk phones for colleagues, do-not-disturb, forwarding and queue login, BLF pickup and the voicemail lamp (1.6.5–1.6.6, see Busy lamps); e-mail templates (1.6.0), Android full-screen calls, call history clean-up and
notification reply (1.6.0), show password (1.6.1), Google sign-in fix and “Forgot your password?”
(1.6.2), help contact on the sign-in page (1.6.3), 23 languages for all new texts (1.6.4). See the
CHANGELOG.
Goal. A “Call us” button for any website. A visitor clicks it and talks to the company over WebRTC in the browser, without a phone or an app. A small WordPress plugin then only has to insert the same code.
Idea: a widget is a virtual trunk. Each widget enters the PBX like a call from a trunk, with its own number that acts as the DID. Routing, time conditions, queues and reports therefore work for widget calls exactly as for calls from a carrier.
Admin page (Integrations → Web widgets). An administrator can create any number of widgets. Each one has:
Embed code with a copy button, one line:
<script src="https://pbx.example.com/widget.js" data-widget="w_8f3k2" async></script>
How a call works.
widget.js draws a floating button on the website.Steps.
widget.js user interface for desktop and mobile browsers.Later: a call-back form (the visitor leaves a number and the PBX calls them), guest chat, video.
The sender can delete a message. Everyone in the conversation then sees “message deleted”, and an attached file is removed from the server’s disk. Changes are needed in the chat service (Go), the web chat and the Android and iOS apps; an administrator setting may limit how long after sending a message can still be deleted.
Attachments are stored on the server’s disk today. An optional S3-compatible storage (AWS S3, MinIO, Wasabi, Backblaze B2 …) would keep large files off the PBX: bucket, key and region on an admin page, a connection test, and a one-time move of existing files. Downloads keep going through the chat service, so access rules stay the same.
The server allows VP8, VP9, and H.264 codecs for WebRTC. Asterisk ConfBridge SFU forwards RTP video streams directly without server-side transcoding, enabling responsive multi-party gallery grid video conferences in browsers, while Follow-Talker mode supports hardware SIP video phones. Includes pre-join device check lobby, screen sharing, email invitations, and Outlook/Google Calendar .ics attachments.
Run AI models on the PBX itself, so audio and recordings never leave the server.
Before building, check each model’s licence (commercial use), its speed on a CPU (most PBX servers have no GPU) and its quality on 8 kHz telephone audio. The published figures (for example the first audio after ~4 ms) have to be measured on our own servers.
Checked (2026-10-09). Both models are Apache-2.0 (commercial use allowed; weights not gated). EMA Lightning on a 2-core i7-7700 without GPU, on ONNX Runtime (since 1.9.2): 8.6–11× faster than real time, a 6.4 s sentence in 0.55 s, model load 1.3–2.4 s, about 150–250 MB of memory, 160 MB of runtime (PyTorch in 1.9.0–1.9.1: 3.4–4.5×, up to 1 GB of memory, 1.1 GB of runtime). EmbeddingGemma 2 (740M parameters, ONNX q4/q8 from onnx-community, measured 2026-10-09 with 68 Turkish test phrases made by EMA at 8 kHz): 1.5–2 GB of memory, 0.9 s per 1.8 s clip on 2 cores, ~700 MB download. Recognising six hotel requests from the audio only 54–62 % (chance 17 %), person/machine from the first 2 s 80 %. The same requests as text were matched 11 of 12 times. Conclusion: understanding needs speech-to-text first, then matching on text; EmbeddingGemma’s audio part is dropped (too heavy, too weak on Turkish speech). See “Model catalogue” below.
Steps.
aipbx-ai service reachable only from the server itself. An
AI → Local models page downloads and removes models, shows their size, asks to accept the
licence, and shows status, RAM/CPU use and a speed test (“does this run in real time here?”).aipbx-ai receives and sends a call’s audio live through
Asterisk’s AudioSocket (already loaded on the servers); the result (chosen destination,
person/machine, recognised request) goes back to the dialplan as channel variables.AI applications with their own numbers (1.10.0: page, numbers, destination, announcement with values). A new page AI → Applications. Each application has a type, its settings and an internal number; it is a destination like an IVR or a queue (DIDs, IVR keys, time conditions) and can be dialled directly. Several applications of the same type work side by side, each with its own settings, for example:
| Number | Application | What it does |
|---|---|---|
| 7101 | Routing by speech: sales line | asks “how can I help?” and sends the caller to Sales, Accounts or Support |
| 7102 | Routing by speech: support line | the same model, other requests and queues |
| 7201 | Announcement with values: balance | “Dear {name}, your balance is {amount}”, read on the fly, then a destination |
| 7202 | Announcement with values: appointment | another template, the same model |
| 7300 | Voice requests: hotel reception | see step 6 |
| 7901 | AI test line | speak and hear what was recognised (request, emotion, person/machine) |
Every application has a limit of simultaneous calls; above it, or when the model is not ready, the caller goes to the normal (keypad) flow. The first type is announcement with values (EMA Lightning only, possible today); its values come from dialplan variables (e.g. the caller’s number) or from a web address of the customer’s own system.
Unrecognised requests go to reception. Every request is logged (room, request, time, handled). The same type serves other places: a clinic (cancelling an appointment), a service desk (fault report), a residential site (calling security). Reading details out of the speech (quantity, time) needs speech recognition, see step 9.
Local model catalogue. Administrators choose, download and try models themselves. Any Hugging Face model of a supported kind can be used; each kind is an engine written once:
| Engine | Job | Models |
|---|---|---|
| EMA Lightning | Turkish speech | 1 (done) |
| Piper | speech, 40+ languages | hundreds of voices (German thorsten, kerstin: CC0) |
| Kokoro | speech: English, French, Spanish, Italian … (no German) | tens of voices, Apache-2.0 |
| Vosk | speech-to-text, streaming, small (TR 35 MB, DE 45 MB, EN ~40 MB) | 20+ languages, Apache-2.0 |
| Whisper (ONNX) | speech-to-text, 99 languages, heavier, more accurate | several sizes, MIT |
| Text embeddings (ONNX) | matching requests, text search | many |
AI → Local models gets: a recommended list (models we measured, with their speed and memory), a Hugging Face search limited to supported kinds (size, licence, language, downloads), “paste a model address”, several models on disk, run/stop (loaded in memory or not) with a memory and disk overview and warnings, and a try panel (type text and listen, compare two voices; speak or upload audio and read the text). Only ONNX and data files are downloaded (no pickle, no remote code); the licence is shown and accepted first, non-commercial licences are flagged; files are recorded with SHA-256; a disk limit (default 5 GB).
Steps: (a) catalogue and several models: download, run, stop, memory/disk (done in 1.9.3); (b) Piper engine and the speech try panel (done in 1.9.3); (c) Kokoro engine (done in 1.9.4); (d) Hugging Face search and pasted addresses (Piper voice list done in 1.9.4); (e) Vosk engine and the speech-to-text try panel (microphone or file) (done in 1.9.4); (f) the recommended list with our measurements; (g) Whisper and text-embedding engines, with the AI applications. Every engine is measured on the CI VM (speed, memory, quality) before it is recommended.
Cloud AI services (first version in 1.9.5: accounts, test, usage, cloud speech to text, engine per job). A separate page AI → Cloud services: provider accounts in one place (API keys encrypted, connection test), each with what it can do — speech, speech-to-text, understanding (language models), embeddings — for example Google AI Studio (Gemini, Gemma), OpenAI, Azure Speech, Google Cloud Speech, ElevenLabs, Deepgram, Groq, OpenRouter. The keys of today’s Cloud TTS page move there; that page stays as the announcement maker.
An engine per job. For each job (speech per language, speech-to-text, understanding) the administrator picks local or cloud from one list, with an optional fallback (cloud unreachable or over its limit → local). The AI applications use these choices, so switching from local to cloud needs no other change. Paid services get a usage counter and a monthly limit; choosing a cloud engine shows that audio and text are sent to that provider (privacy, KVKK/GDPR).
Two products seen as examples: CentraVox (custom Turkish voice assistant: inbound and outbound calls, appointments with calendar and clash checks, confirmation and reminder calls, assistants handing over to each other with the whole conversation, recordings with transcripts, asking the panel questions; critical promises are spoken by the system, not the language model) and talku.ai (inbound voice agents as a service, attached to an existing PBX through a SIP address, ~650 ms response, n8n/Zapier, priced per minute). For AiPBX this suggests, in order: (1) a destination “external AI assistant (SIP)” so any such service can take calls while recording and CDR stay here; (2) transcripts of call recordings in the CDR, searchable; (3) an own assistant (cloud language model, local Turkish voice, allowed actions only, hand-over to a person when unsure); (4) appointments with a calendar and outbound confirmation calls; (5) several assistants with hand-over. Not scheduled yet.
The native iOS app (AiPBX-ios) maintains full feature parity with the Android app:
UNTextInputNotificationAction).ImageViewerOverlay), pan, double-tap zoom, and iOS share sheet..lproj).1.50.35 (build 75).The generated inbound dialplan uses the pattern _., which Asterisk warns about on every reload
(“The use of ‘_.’ for an extension is strongly discouraged”). Replacing it with _X. (or a
pattern that also accepts +) removes the warnings from the log; it has to be checked against
DIDs that start with + before the change.
Goal. Multi-key SIP phones (and their expansion modules) show the state of many colleagues at once: a receptionist or a manager typically watches 10–15 people, an operator console 40–100. Each key has the colleague’s name and a lamp:
| Lamp | Meaning | Pressing the key |
|---|---|---|
| off / green | free | calls them |
| red | on the phone | calls them (or transfers the current call to them) |
| blinking | their phone rings | picks up that call |
| (optional) | do not disturb / not registered | — |
The message lamp shows new voicemail.
Today. Every extension already has an Asterisk hint (desk phone, web phone and app together)
in from-internal-pbx. Desk phones, however, use the context of their dial permission group, and
whether their subscriptions (SUBSCRIBE) reach those hints has to be tested with a real phone. Desk
phones also get no voicemail lamp: their endpoints have no mailboxes=.
Plan.
subscribe_context (or include from-internal-pbx) on desk phone endpoints so a key for
extension 1001 always finds its hint; test with Yealink, Grandstream and Fanvil (including an
expansion module) and with a softphone in CI.*21 + extension, already exists); transfer the current call by pressing a busy or free key.device_state_busy_at so a
user with several devices shows busy correctly.mailboxes=<ext>@default on desk phone endpoints, so the phone shows new voicemail
and the count.*95), do-not-disturb, call forwarding, a
day/night (time condition) switch, conference rooms and parked calls, through custom device
states.Goal. A new desk phone works within a minute: plug it in, it fetches its configuration from AiPBX and registers with the right extension, keys and settings, without anyone typing on it.
Admin page (Network & devices → Phones):
*97), BLF keys (item 8), a dial plan and the phone’s own web
admin password (generated and kept per phone). An administrator can override settings per model
or per phone.check-sync, so the phone reloads its configuration at
once), reboot, firmware upload per model.Delivery and security. Configurations are served over HTTPS by the portal, one URL per
phone with a random token (/provision/<token>/<file>), never readable from outside the allowed
networks. They contain the SIP password, so every phone gets its own random password and every
download is logged. Plain TFTP and HTTP serve only the first step for phones that cannot start
with HTTPS (see item 10).
Later: SIP plug-and-play (Yealink/Fanvil/Snom phones ask the network for their provisioning server by multicast; a small listener answers with AiPBX’s URL), so even the DHCP option is not needed.
Goal. Phones find the provisioning server by themselves: the DHCP server tells them its address (option 66), and TFTP serves the files of phones that need it.
Admin page (Network & devices → Network services):
aipbx-priv root helper like the other system settings. The firewall opens UDP 67/69 only on
the chosen interface.Order. Item 9 (provisioning over HTTPS) first, because it is useful on its own with the company’s existing DHCP server; item 10 then makes the start automatic.
Planned for later. Since 1.8.0 each IVR has a read-only Call flow view (the whole path as a tree: keys, no input, invalid key, sub-menus, time conditions and announcements). The next step is editing on that view: dragging destinations onto keys, adding sub-menus and announcements in place, and seeing the changes before Apply. Until then keys are edited in the IVR dialogs.
Done in 1.33.0: health check Server address, Network settings → Apply new address and
sudo aipbx-readdress; see Network settings. Planned 2026-10-16. Today the server’s IP address is written into many places, at install time or
by hand, and nothing notices when it changes (a new DHCP lease, a move to another network, a
cloned VM). Calls then break in ways that are hard to trace: TURN has no audio, desk phones
register to the old address, the portal’s certificate no longer matches.
Where the address lives today
| Place | Written by | Holds |
|---|---|---|
sys_settings.server_ip |
Asterisk settings | RTP ice_host_candidates (SyncRtpSettings) |
pjsip_external_ip, pjsip_local_net |
Asterisk settings | NAT: public address, local networks of every transport |
provision_sip_server, provision_base_url, provision_syslog, provision_ntp |
Phones → Provisioning settings | what desk phones are told (SIP server, files, syslog, time) |
provision_allowed_networks, netsvc_* |
Phones, Network services | allowed networks, DHCP range, gateway, option 66 URL |
/etc/turnserver.conf |
install.sh |
relay-ip, allowed-peer-ip (1.32.0) |
| self-signed certificate | install.sh / aipbx-cert |
IP in the subject alternative name |
aipbx-mdns unit |
install.sh |
mDNS alias → address |
| the phones themselves | phone menu or DHCP | boot / file server (NEC), until the next provisioning |
Plan
hostname -I with the stored ones
(server_ip, coturn relay-ip, provisioning addresses) and raises an alarm (mail, banner on
the portal): “the server’s address changed from A to B”.sudo aipbx-readdress <old> <new> on the command line, both through aipbx-priv.
relay-ip / allowed-peer-ip;
re-issue a self-signed certificate that names the IP; update the mDNS alias; regenerate PJSIP
transports, RTP, provisioning and TFTP/FTP phone files; DHCP options when DHCP runs here.Done in 1.33.0 (Network & devices → Network settings), except the last point: changing the server’s own address, gateway and DNS with a roll-back is still open. Planned 2026-10-16. Network settings are spread over Asterisk settings (external IP, local networks, RTP ports), Phones → Provisioning settings (addresses for the phones, allowed networks) and Network services. One page collects them:
netplan try does: the old settings come back after
2 minutes unless the change is confirmed from the new address. Changing the address here runs
item 12.Done in 1.33.0 as below (Lines and Panel kept their entries). Planned 2026-10-16, to do together with 12 and 13. The PBX group holds 16 entries, network and desk-phone pages sit between ring groups and IVRs, and Admin mixes users, settings and system pages. Proposed groups:
| Group | Entries |
|---|---|
| Panel | Overview, My phone, Chat, Reports |
| Lines | Trunks, Inbound routes, Outbound routes, Dial permissions |
| PBX | Extensions, IVR, Time plans, Ring groups, Queues, Conferences, Boss–secretary, Hangup actions, Sounds, Feature codes, Active codes |
| Network & devices (new) | Network settings (13), Network services, Phones (provisioning), Phone logs |
| Call centre | unchanged |
| Fax | unchanged |
| AI | unchanged |
| Integrations | unchanged |
| Security | Firewall, Fail2ban, Certificates, Audit log |
| System (was Admin) | Users, Roles, Asterisk settings, Appearance, Push, E-mail, Fax e-mail, File storage, Pending changes, System update, Health checks, Help |
Old addresses keep working (the routes do not change, only the menu). The role matrix and the module keys stay as they are.
Done in 1.50.36 (Network → Reverse Proxy & Security → Certificates). Planned for issue #148 and delivered under Spec 003:
/reverse-proxy) with trusted CIDR proxy configuration, TLS termination modes, and live HTTP header inspection./ws and /chat/ws pass-through.*.<domain>) in /certificates and conf/sbin/aipbx-cert, enabling SSL/TLS issuance on private/internal PBX installations without public port 80 exposure.